home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / recov / recovery.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  74KB  |  2,642 lines

  1. /* 
  2.  * recovery.c --
  3.  *
  4.  *    The routines here maintain up/down state about other hosts.
  5.  *    Other modules register as clients of the recovery module,
  6.  *    and can then ask to be called back when some other host crashes
  7.  *    or reboots.  Modules always get called back when someone crashes,
  8.  *    and then they have the option of being called back when the
  9.  *    host reboots.  Regular message traffic plus explicit pinging
  10.  *    are used to track the state of the other hosts.  Pinging is
  11.  *    only done if some module is explicitly interested in a host.
  12.  *
  13.  *    Recov_HostAlive and Recov_HostDead are used by RPC to tell us when
  14.  *    a messages have arrived, or if transactions have timed out.
  15.  *    Recov_IsHostDown is used to query the state of another host,
  16.  *    Recov_RebootCallBack is used to get a callback upon a reboot, and
  17.  *    Recov_WaitForHost is used to block a process until a host reboots.
  18.  *    (Recov_WaitForHost isn't used much.  Instead, modules rely on the
  19.  *    recovery callbacks to indicate that a host is back to life, and
  20.  *    they block processes in their own way.)
  21.  *
  22.  *    Note: A synchronization hook is provided by Recov_HostAlive;  its
  23.  *    caller can be blocked if crash recovery actions are in progress.
  24.  *
  25.  * Copyright 1987 Regents of the University of California
  26.  * All rights reserved.
  27.  */
  28.  
  29. #ifndef lint
  30. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/recov/recovery.c,v 9.27 92/12/13 18:20:14 mgbaker Exp $ SPRITE (Berkeley)";
  31. #endif /* not lint */
  32.  
  33.  
  34. #include <sprite.h>
  35. #include <recov.h>
  36. #include <sync.h>
  37. #include <net.h>
  38. #include <rpc.h>
  39. #include <hash.h>
  40. #include <stdlib.h>
  41. #include <trace.h>
  42. #include <fsutil.h>
  43. #include <bstring.h>
  44. #include <stdio.h>
  45. #include <devClientDev.h>
  46.  
  47. /*
  48.  * Other kernel modules arrange call-backs when a host crashes or reboots.
  49.  * The following list structure is used to keep these.  The calling
  50.  * sequence of the callbacks is as follows:
  51.  *    (*proc)(spriteID, clientData)
  52.  * Use Recov_CrashRegister and Recov_RebootRegister to set up the call backs.
  53.  */
  54.  
  55. typedef struct {
  56.     List_Links    links;
  57.     void    (*proc)();
  58.     int        refCount;
  59.     ClientData    data;
  60. } NotifyElement;
  61.  
  62. /*
  63.  * There is a single list of crash call backs, it isn't per machine
  64.  * like the reboot callbacks.
  65.  */
  66. static List_Links    crashCallBackList;
  67.  
  68. /*
  69.  * recov_CrashDelay is the grace period given when another host
  70.  * is apparently down.  Reboots are still detected so that
  71.  * the crash callbacks will get called to clean up.
  72.  */
  73. unsigned int recov_CrashDelay;
  74.  
  75. /*
  76.  * Statistics about the recovery module.
  77.  */
  78. Recov_Stats recov_Stats;
  79.  
  80. /*
  81.  * For per-client statistics about recovery on the server.
  82.  * This is only used for getting stats, and isn't used for keeping
  83.  * track of client state.
  84.  * This amounts to a per-host list, in array form.
  85.  * Each host has numTries elements in the array.  The spriteID and numTries
  86.  * fields are only initialized in the first element.
  87.  */
  88. typedef    struct    RecovPerHostInfo {
  89.     int        spriteID;    /* Sprite ID of client. */
  90.     Time    start;        /* First recovery attempt. */
  91.     Time    finished;    /* First recovery attempt finished. */
  92.     int        numTries;    /* Number of recovery attempts. */
  93.     int        numHandles;    /* Number of reopens requested. */
  94.     int        numSuccessful;    /* Handles successfully recovered. */
  95. } RecovPerHostInfo;
  96.  
  97.  
  98.  
  99. /*
  100.  * The state of other hosts is kept in a hash table keyed on SpriteID.
  101.  * This state is maintained by Recov_HostAlive and Recov_HostDead, which are
  102.  * called in turn after packet reception or RPC timeout, respectively.
  103.  * Recov_HostDead is also called by the Rpc_Daemon if it can't get an
  104.  * explicit acknowledgment from a client.
  105.  */
  106. static Hash_Table    recovHashTableStruct;
  107. static Hash_Table    *recovHashTable = &recovHashTableStruct;
  108.  
  109. typedef    struct    RecovStampList {
  110.     List_Links    timeStampList;
  111.     Timer_Ticks    start;
  112.     Timer_Ticks    finished;
  113.     int        numHandles;        /* Handles since last time. */
  114.     int        numSuccessful;        /* Successful last time. */
  115. } RecovStampList;
  116.  
  117. typedef struct RecovHostState {
  118.     int            state;        /* flags defined in .h file */
  119.     int            clientState;    /* flags defined in recov.h */
  120.     int            spriteID;    /* Sprite Host ID */
  121.     unsigned int    bootID;        /* Boot timestamp from RPC header */
  122.     Time        time;        /* Time of last message */
  123.     Sync_Condition    alive;        /* Notified when host comes up */
  124.     Sync_Condition    recovery;    /* Notified when recovery is complete */
  125.     List_Links        rebootList;    /* List of callbacks for when this
  126.                      * host reboots. */
  127.     int            numFailures;    /* Times a failure occurs during the
  128.                      * reboot callbacks.  Such a failure
  129.                      * triggers a retry of the reboot
  130.                      * callbacks. */
  131.     /*
  132.      * The following fields are used in the tracing of the recovery module.
  133.      */
  134.     Timer_Ticks        start;        /* Time that recovery is started. */
  135.     Timer_Ticks        finished;    /* Time recovery attempt  finishes. */
  136.     int            numTries;    /* Number of times recov attempted. */
  137.     int            numHandles;    /* Handles requested. */
  138.     int            numSuccessful;    /* Successful handles. */
  139.     int            currentHandles;    /* Temporary info. */
  140.     int            currentSuccessful;
  141.     List_Links        timeStampList;    /* List of time stamps for recovery. */
  142.     int            oldState;    /* Used for screening out trace recs. */
  143.     ClientData        callToken;    /* Token for timeout callback to
  144.                      * do recovery with server if server
  145.                      * didn't contact us.  We must be
  146.                      * able to deschedule the callback, so
  147.                      * that's what this token is for. */
  148.     Sync_Condition    waitForServer;    /* Waiting for server-driven recovery
  149.                      * to wake us.  Or else for our
  150.                      * timeout to wake us.
  151.                      */
  152. } RecovHostState;
  153.  
  154. #define RECOV_INIT_HOST(hostPtr, zspriteID, zstate, zbootID) \
  155.     hostPtr = (RecovHostState *) malloc(sizeof (RecovHostState)); \
  156.     (void)bzero((Address)hostPtr, sizeof(RecovHostState)); \
  157.     List_Init(&(hostPtr)->rebootList); \
  158.     List_Init(&(hostPtr)->timeStampList);\
  159.     (hostPtr)->spriteID = zspriteID; \
  160.     (hostPtr)->state = zstate; \
  161.     (hostPtr)->bootID = zbootID; \
  162.     (hostPtr)->numFailures = 0; \
  163.     (hostPtr)->oldState = 0; \
  164.     (hostPtr)->callToken = (ClientData) NIL;
  165.  
  166. /*
  167.  * Access to the hash table is monitored.
  168.  */
  169. static Sync_Lock recovLock;
  170. #define LOCKPTR (&recovLock)
  171.  
  172.  
  173. /*
  174.  * recov_PrintLevel defines how noisey we are about other hosts.
  175.  *    Values for the print level should be defined in increasing order.
  176.  */
  177. int recov_PrintLevel = RECOV_PRINT_REBOOT;
  178.  
  179. #define RecovHostPrint(level, spriteID, message) \
  180.     if (recov_PrintLevel >= level) { \
  181.         Sys_HostPrint(spriteID, message); \
  182.     }
  183.  
  184. Trace_Header recovTraceHdr;
  185. Trace_Header *recovTraceHdrPtr = &recovTraceHdr;
  186. int recovTraceLength = 200;
  187. Boolean recovTracing = TRUE;
  188.  
  189. /*
  190.  * TRUE if we're using transparent server recovery (using recovery box).
  191.  */
  192. #ifdef RECOV_TRANSPARENT
  193. Boolean    recov_Transparent = TRUE;
  194. #else
  195. Boolean    recov_Transparent = FALSE;
  196. #endif /* RECOV_TRANSPARENT */
  197.  
  198. /*
  199.  * True if we should batch together multiple reopens in an rpc.
  200.  */
  201. Boolean    recov_BulkHandles = TRUE;
  202.  
  203. /*
  204.  * TRUE if the clients should ignore the fact that a server is able to
  205.  * do transparent recovery.  This will be FALSE except for some testing.
  206.  */
  207. Boolean recov_ClientIgnoreTransparent = FALSE;
  208. /*
  209.  * This one should usually be true: okay to do fast reboot as far as
  210.  * reusing text and initialized heap, but this doesn't have to include
  211.  * using the recovery box.
  212.  */
  213. #ifdef RECOV_NOCOPY
  214. Boolean    recov_DoInitDataCopy = FALSE;
  215. #else
  216. Boolean    recov_DoInitDataCopy = TRUE;
  217. #endif /* RECOV_NOCOPY */
  218.  
  219. /*
  220.  * TRUE if we're recovering using server-driven method.
  221.  * This is set to true by an initialization routine that is called
  222.  * as a result of the user-level daemon contacting the kernel.
  223.  */
  224. Boolean    recov_ServerDriven = FALSE;
  225.  
  226. /*
  227.  * TRUE if the clients should ignore server-driven recovery.
  228.  */
  229. Boolean recov_ClientIgnoreServerDriven = TRUE;
  230. /*
  231.  * Don't bother to reopen files that only have clean blocks in the cache.
  232.  * Invalidate their clean cache blocks and scavenge the handles.
  233.  * This variable and recov_SkipCleanFiles should never both be set true!
  234.  */
  235. Boolean    recov_IgnoreCleanFiles = FALSE;
  236.  
  237. /*
  238.  * Don't bother to reopen files that only have clean blocks in the cache.
  239.  * Just leave alone their cache blocks and handles.
  240.  * This variable and recov_IgnoreCleanFiles should never both be set true!
  241.  */
  242. Boolean    recov_SkipCleanFiles = TRUE;
  243.  
  244. /*
  245.  * Are we blocking out some rpc's because server-driven recovery is
  246.  * in progress?
  247.  */
  248. Boolean    recov_BlockingRpcs = FALSE;
  249.  
  250. /*
  251.  * Forward declarations.
  252.  */
  253.  
  254. static void CrashCallBacks _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  255. static void CallBacksDone _ARGS_((int spriteID));
  256. static void MarkRecoveryComplete _ARGS_((int spriteID));
  257. static void GetRebootList _ARGS_((List_Links *notifyListHdr, int spriteID));
  258. static char *GetState _ARGS_((int state));
  259. static void PrintExtraState _ARGS_((RecovHostState *hostPtr));
  260.  
  261.  
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Recov_Init --
  267.  *
  268.  *    Set up the data structures used by the recovery module.
  269.  *
  270.  * Results:
  271.  *    None.
  272.  *
  273.  * Side effects:
  274.  *    None.
  275.  *
  276.  *----------------------------------------------------------------------
  277.  */
  278.  
  279. void
  280. Recov_Init()
  281. {
  282.     Sync_LockInitDynamic(&recovLock, "Recov:recovLock");
  283.     Hash_Init(recovHashTable, 8, HASH_ONE_WORD_KEYS);
  284.     List_Init(&crashCallBackList);
  285.     Trace_Init(recovTraceHdrPtr, recovTraceLength,
  286.         sizeof(RecovTraceRecord), 0);
  287.     Fsutil_InitBulkReopenTables();
  288.     recov_CrashDelay = (unsigned int)(timer_IntOneMinute);
  289.     RecovPingInit();
  290.     return;
  291. }
  292.  
  293. /*
  294.  *----------------------------------------------------------------------
  295.  *
  296.  * Recov_CrashRegister --
  297.  *
  298.  *    This procedure is used to register a crash callback procedure.
  299.  *    This is typically done once at boot time by each module that
  300.  *    is interested in learning about the failure of other hosts.
  301.  *    When other hosts are (apparently) down the recovery module
  302.  *    calls back to other modules that have registered via this procedure.
  303.  *    This allows those other modules to clean up any state associated
  304.  *    with the crashed host.
  305.  *    
  306.  * Results:
  307.  *    None.
  308.  *
  309.  * Side effects:
  310.  *    Callback entry added to the crash call-back list.
  311.  *
  312.  *----------------------------------------------------------------------
  313.  */
  314. void
  315. Recov_CrashRegister(crashCallBackProc, crashData)
  316.     void    (*crashCallBackProc)();
  317.     ClientData    crashData;
  318. {
  319.     register    NotifyElement    *notifyPtr;
  320.  
  321.     notifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  322.     notifyPtr->proc = crashCallBackProc;
  323.     notifyPtr->data = crashData;
  324.     List_InitElement((List_Links *) notifyPtr);
  325.     List_Insert((List_Links *) notifyPtr, LIST_ATREAR(&crashCallBackList));
  326.     return;
  327. }
  328.  
  329. /*
  330.  *----------------------------------------------------------------------
  331.  *
  332.  * Recov_RebootRegister --
  333.  *
  334.  *    Schedule a callback for when a particular host reboots.
  335.  *    To make sure we detect a crash, the recovery module has to
  336.  *    periodically check on the state of the target host.
  337.  *
  338.  * Results:
  339.  *    None.
  340.  *
  341.  * Side effects:
  342.  *    This initiate a background callback to check-up on the host's state.
  343.  *
  344.  *----------------------------------------------------------------------
  345.  */
  346.  
  347. ENTRY void
  348. Recov_RebootRegister(spriteID, rebootCallBackProc, rebootData)
  349.     int spriteID;
  350.     void (*rebootCallBackProc)();
  351.     ClientData rebootData;
  352. {
  353.     Hash_Entry *hashPtr;
  354.     RecovHostState *hostPtr;
  355.     register NotifyElement *notifyPtr;
  356.     Boolean found = FALSE;
  357.  
  358.     LOCK_MONITOR;
  359.  
  360.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  361.     panic("Recov_RebootRegister, bad hostID %d\n", spriteID);
  362.     } else {
  363.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  364.     if (hashPtr->value == (Address)NIL) {
  365.         RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  366.         hashPtr->value = (Address)hostPtr;
  367.         RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  368.     } else {
  369.         hostPtr = (RecovHostState *)hashPtr->value;
  370.     }
  371.     /*
  372.      * Save the callback while avoiding duplications.
  373.      */
  374.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  375.         if (notifyPtr->proc == rebootCallBackProc &&
  376.         notifyPtr->data == rebootData) {
  377.         found = TRUE;
  378.         break;
  379.         }
  380.     }
  381.     if (!found) {
  382.         notifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  383.         notifyPtr->proc = rebootCallBackProc;
  384.         notifyPtr->data = rebootData;
  385.         notifyPtr->refCount = 1;
  386.         List_InitElement((List_Links *)notifyPtr);
  387.         List_Insert((List_Links *)notifyPtr,
  388.             LIST_ATFRONT(&hostPtr->rebootList));
  389.     } else {
  390.         notifyPtr->refCount++;
  391.     }
  392.     /*
  393.      * Mark the host as being interesting, and add it to the ping
  394.      * list if necessary.
  395.      */
  396.     hostPtr->state |= RECOV_PINGING_HOST;
  397.     RecovAddHostToPing(spriteID);
  398.     }
  399.     UNLOCK_MONITOR;
  400.     return;
  401. }
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * Recov_RebootUnRegister --
  407.  *
  408.  *    Remove a callback for when a particular host reboots.  This is
  409.  *    used after we are no longer interested in a host rebooting.
  410.  *
  411.  * Results:
  412.  *    None.
  413.  *
  414.  * Side effects:
  415.  *    Nukes the reboot procedure.  If all interested parties remove their
  416.  *    reboot callbacks then the periodic check of the other host is
  417.  *    stopped.
  418.  *
  419.  *----------------------------------------------------------------------
  420.  */
  421.  
  422. ENTRY void
  423. Recov_RebootUnRegister(spriteID, rebootCallBackProc, rebootData)
  424.     int spriteID;
  425.     void (*rebootCallBackProc)();
  426.     ClientData rebootData;
  427. {
  428.     Hash_Entry *hashPtr;
  429.     RecovHostState *hostPtr;
  430.     register NotifyElement *notifyPtr;
  431.     Boolean found = FALSE;
  432.  
  433.     LOCK_MONITOR;
  434.  
  435.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  436.     panic("Recov_RebootUnRegister, bad hostID %d\n", spriteID);
  437.     } else {
  438.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  439.     if (hashPtr->value == (Address)NIL) {
  440.         RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  441.         hashPtr->value = (Address)hostPtr;
  442.         RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  443.     } else {
  444.         hostPtr = (RecovHostState *)hashPtr->value;
  445.     }
  446.     /*
  447.      * Look for the matching callback.
  448.      */
  449.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  450.         if (notifyPtr->proc == rebootCallBackProc &&
  451.         notifyPtr->data == rebootData) {
  452.         found = TRUE;
  453.         break;
  454.         }
  455.     }
  456.     if (found) {
  457.         notifyPtr->refCount--;
  458.         if (notifyPtr->refCount <= 0) {
  459.         int        num;
  460.         /*
  461.          * Mousetrap for debugging recovery reference count problem.
  462.          */
  463.         if (notifyPtr->proc == (void((*)())) Fsutil_Reopen) {
  464.  
  465.             if (recov_PrintLevel >= RECOV_PRINT_CRASH) {
  466.             printf(
  467.         "Recov: deleting Fsutil_Reopen for server %d ref count %d\n",
  468.                 spriteID, notifyPtr->refCount);
  469.             }
  470.             /*
  471.              * We want to panic if we still have handles for
  472.              * this server.
  473.              */
  474.             num = Fsutil_TestForHandles(spriteID);
  475.             /*
  476.              * This routine is called before the handle is removed,
  477.              * so we must take into account the fact that it still
  478.              * exists in the handle table.
  479.              */
  480.             if (num > 1) {
  481.             printf("%d file and device handles remain\n", num);
  482.             panic("Shouldn't have deleted it - handles remain!\n");
  483.             }
  484.         }
  485.         List_Remove((List_Links *)notifyPtr);
  486.         free((Address)notifyPtr);
  487.         }
  488.     }
  489.     }
  490.     UNLOCK_MONITOR;
  491.     return;
  492. }
  493.  
  494. /*
  495.  *----------------------------------------------------------------------
  496.  *
  497.  * Recov_HostAlive --
  498.  *
  499.  *    Mark the host as being alive.  This is called when we've received
  500.  *    a message from the host.  It uses state from the host table and
  501.  *    the bootID parameter to detect reboots.  If a reboot is detected,
  502.  *    but we thought the host was up, then the Crash call-backs are invoked.
  503.  *    In any case, a reboot invokes the Reboot call-backs, if any.
  504.  *
  505.  *    This procedure is called from client RPC upon successful completion
  506.  *    of an RPC, and by server RPC upon reciept of a client request.
  507.  *    These two cases are identified by the 'asyncRecovery' parameter.
  508.  *    Servers want synchronous recovery so they don't service anything
  509.  *    until state associated with that client has been cleaned up via
  510.  *    the Crash call-backs.  So Recov_HostAlive blocks (if !asyncRecovery)
  511.  *    until the crash call-backs are complete.  Clients don't have the
  512.  *    same worries so they let the crash call-backs complete in the
  513.  *    background (asyncRecovery is TRUE).
  514.  *
  515.  * Results:
  516.  *    None.
  517.  *
  518.  * Side effects:
  519.  *    Updates the boot timestamp of the other host.  Procedures installed
  520.  *    with Recov_CrashRegister are called when the bootID changes.  A
  521.  *    timestamp of when this message was received is obtained from the
  522.  *    "cheap" clock so we can tell later if there has been recent message
  523.  *    traffic.
  524.  *
  525.  *----------------------------------------------------------------------
  526.  */
  527.  
  528. ENTRY void
  529. Recov_HostAlive(spriteID, bootID, asyncRecovery, rpcNotActive, recovType)
  530.     int spriteID;        /* Host ID of the message sender */
  531.     unsigned int bootID;    /* Boot time stamp from message header */
  532.     Boolean asyncRecovery;    /* TRUE means do recovery call-backs in
  533.                  * the background. FALSE causes the process
  534.                  * to wait until crash recovery is complete. */
  535.     Boolean rpcNotActive;    /* This is a flag propogated from the rpc
  536.                  * packet header.  If set it means the RPC
  537.                  * system on the remote host isn't fully
  538.                  * turned on.  Reboot recovery is delayed
  539.                  * until this changes. */
  540.     unsigned int recovType;    /* Whether the host that's alive went through
  541.                  * a fast boot or is doing server-driven
  542.                  * recovery or not. */
  543. {
  544.     register    Hash_Entry *hashPtr;
  545.     register    RecovHostState *hostPtr;
  546.     int        hostState = -1;
  547.  
  548.     LOCK_MONITOR;
  549.     if (spriteID == NET_BROADCAST_HOSTID || bootID == 0 || sys_ShuttingDown) {
  550.     /*
  551.      * Don't track the broadcast address.  Also ignore zero valued
  552.      * bootIDs.  These come from hosts at early boot time, or
  553.      * in certain error conditions like trying to send too much
  554.      * data in a single RPC.  Also don't bother to check things
  555.      * where we are shutting down the system because we don't want 
  556.      * RPCs for the cache data to get blocked.
  557.      */
  558.     UNLOCK_MONITOR;
  559.     return;
  560.     }
  561.  
  562.     recov_Stats.packets++;
  563.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  564.     if (hashPtr->value == (Address)NIL) {
  565.     /*
  566.      * Initialize the host's state. This is the first time we've talked
  567.      * to it since we've been up, so take no action.
  568.      */
  569.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_HOST_ALIVE, bootID);
  570.     hashPtr->value = (Address)hostPtr;
  571.  
  572.     RecovHostPrint(RECOV_PRINT_IF_UP, spriteID, "is up\n");
  573.     RECOV_TRACE(spriteID, RECOV_HOST_ALIVE, RECOV_CUZ_INIT);
  574.     hostState = DEV_CLIENT_STATE_NEW_HOST;
  575.     } else {
  576.     hostPtr = (RecovHostState *)hashPtr->value;
  577.     }
  578.     /*
  579.      * Have to read the clock in order to suppress repeated pings,
  580.      * see Recov_GetHostState and Recov_IsHostDown.
  581.      */
  582.     Timer_GetTimeOfDay(&hostPtr->time, (int *)NIL, (Boolean *)NIL);
  583.     /*
  584.      * Check for a rebooted peer by comparing boot time stamps.
  585.      */
  586.     if (hostPtr->bootID != bootID) {
  587.     if (hostPtr->bootID != 0) {
  588.         RecovHostPrint(RECOV_PRINT_REBOOT, spriteID, "rebooted\n");
  589.     } else {
  590.         /*
  591.          * We initialized state before talking to the host the first time.
  592.          * The state is 'unknown' so we won't do crash call-backs.
  593.          */
  594.     }
  595.     hostPtr->bootID = bootID;
  596.     RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_REBOOT);
  597.     if (hostPtr->state &
  598.         (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING)) {
  599.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  600.             "Undetected crash occurred.\n");
  601.         /*
  602.          * A crash occured un-detected.  We do the crash call-backs
  603.          * first, and block server processes in the meantime.
  604.          * RECOV_CRASH_CALLBACKS flag is cleared by CrashCallBacks.
  605.          */
  606.         hostPtr->state &= ~(RECOV_HOST_ALIVE|RECOV_HOST_DEAD);
  607.         hostPtr->state |= RECOV_HOST_BOOTING;
  608.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH_UNDETECTED);
  609.         if ((hostPtr->state & RECOV_CRASH_CALLBACKS) == 0) {
  610.         hostPtr->state |= RECOV_CRASH_CALLBACKS;
  611.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH_UNDETECTED);
  612.         Proc_CallFunc(CrashCallBacks, (ClientData)spriteID, 0);
  613.         }
  614.     }
  615.     } else  if ( ! (hostPtr->state &
  616.         (RECOV_CRASH_CALLBACKS|RECOV_WANT_RECOVERY)) &&
  617.         (hostPtr->state & RECOV_HOST_ALIVE)) {
  618.     /*
  619.      * Fast path.  We already think the other host is up, it didn't
  620.      * reboot, we don't want recovery, and there are no pending
  621.      * crash call-backs to synchronize with.
  622.      */
  623.     goto exit;
  624.     }
  625.     /*
  626.      * Block servers until crash recovery actions complete.
  627.      * This prevents servicing requests from clients until after the
  628.      * recovery actions complete.
  629.      */
  630.     if (! asyncRecovery) {
  631.     RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Async recovery false.\n");
  632.     while (hostPtr->state & RECOV_CRASH_CALLBACKS) {
  633.         (void)Sync_Wait(&hostPtr->recovery, FALSE);
  634.         if (sys_ShuttingDown) {
  635.         UNLOCK_MONITOR;
  636.         Proc_Exit(1);
  637.         }
  638.     }
  639.     }
  640.     /*
  641.      * Now that we've taken care of crash recovery, we see if the host
  642.      * is newly up.  If so, invoke any reboot call-backs and notify
  643.      * waiting processes. This means clientA (us) may start
  644.      * re-opening files from serverB (the other guy) at the same time
  645.      * as clientA (us) is closing files that serverB had had open.
  646.      * ie. both the crash and reboot call backs may proceed in parallel.
  647.      */
  648.     switch(hostPtr->state &
  649.        (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD)) {
  650.         case RECOV_STATE_UNKNOWN:    /* This is zero, no bits set */
  651.         /*
  652.          * We have uninitialized state for the host, mark it alive.
  653.          */
  654.         RecovHostPrint(RECOV_PRINT_IF_UP, spriteID, "is up\n");
  655.         if (rpcNotActive) {
  656.         hostPtr->state |= RECOV_HOST_BOOTING;
  657.         } else {
  658.         hostPtr->state |= RECOV_HOST_ALIVE;
  659.         hostState = DEV_CLIENT_STATE_NEW_HOST;
  660.         }
  661.         break;
  662.     case RECOV_HOST_ALIVE:
  663.         /*
  664.          * Host already alive.  We may still want recovery at this
  665.          * point.  See CallBacksDone.
  666.          */
  667.         RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Already up.\n");
  668.         break;
  669.     case RECOV_HOST_BOOTING:
  670.         /*
  671.          * See if a booting host is ready yet.
  672.          */
  673.         RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Booting, set recov.\n");
  674.         if (! rpcNotActive) {
  675.         hostPtr->state &= ~RECOV_HOST_BOOTING;
  676.         hostPtr->state |= RECOV_HOST_ALIVE|RECOV_WANT_RECOVERY;
  677.         hostState = DEV_CLIENT_STATE_NEW_HOST;
  678.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_WAS_BOOTING);
  679.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  680.             "Booting, set alive, recov.\n");
  681.         }
  682.         break;
  683.     case RECOV_HOST_DEAD:
  684.         /*
  685.          * See if the host is newly booting or back from a net partition.
  686.          */
  687.         if (rpcNotActive) {
  688.         hostPtr->state |= RECOV_HOST_BOOTING;
  689.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_NOW_BOOTING);
  690.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  691.             "Dead or dying, set booting.\n");
  692.         } else {
  693.         hostPtr->state |= (RECOV_HOST_ALIVE|RECOV_WANT_RECOVERY);
  694.         hostState = DEV_CLIENT_STATE_NEW_HOST;
  695.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_WAS_DEAD);
  696.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  697.             "Dead, dying, set want recov.\n");
  698.         }
  699.         hostPtr->state &= ~(RECOV_HOST_DEAD);
  700.         break;
  701.     default:
  702.         printf("Unexpected recovery state <%x> for ", hostPtr->state);
  703.         Sys_HostPrint(spriteID, "\n");
  704.         break;
  705.     }
  706.     if (recovType & RECOV_FAST_BOOT) {
  707.     if (!(hostPtr->state & RECOV_FAST_BOOT)) {
  708.         printf("Recov_HostAlive: setting state for host %d to FAST_BOOT\n",
  709.             spriteID);
  710.     }
  711.     hostPtr->state |= RECOV_FAST_BOOT;
  712.     } else {
  713.     if ((hostPtr->state & RECOV_FAST_BOOT)) {
  714.         printf("Recov_HostAlive: removing FAST_BOOT state for host %d\n",
  715.             spriteID);
  716.     }
  717.     hostPtr->state &= ~RECOV_FAST_BOOT;
  718.     }
  719.     /* Test whether it's trying to do more than one kind of recovery? XXX */
  720.     if (recovType & RECOV_SERVER_DRIVEN) {
  721.     if (!(hostPtr->state & RECOV_SERVER_DRIVEN)) {
  722.         printf(
  723.         "Recov_HostAlive: setting state for host %d to SERVER_DRIVEN\n",
  724.         spriteID);
  725.     }
  726.     hostPtr->state |= RECOV_SERVER_DRIVEN;
  727.     } else {
  728.     if ((hostPtr->state & RECOV_SERVER_DRIVEN)) {
  729.         printf(
  730.         "Recov_HostAlive: removing SERVER_DRIVEN state for host %d\n",
  731.         spriteID);
  732.     }
  733.     hostPtr->state &= ~RECOV_SERVER_DRIVEN;
  734.     }
  735.     /*
  736.      * After a host comes up enough to support RPC service, we
  737.      * initiate reboot recovery if needed.
  738.      */
  739.     if ((hostPtr->state & RECOV_WANT_RECOVERY) &&
  740.     (hostPtr->state & RECOV_HOST_ALIVE) &&
  741.     ((hostPtr->state & RECOV_REBOOT_CALLBACKS) == 0)) {
  742.     hostPtr->state &= ~RECOV_WANT_RECOVERY;
  743.     hostPtr->state |= RECOV_REBOOT_CALLBACKS;
  744.     RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_SCHED_CALLBACK);
  745.     RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  746.         "Want recov, etc, callbacks.\n");
  747.     Proc_CallFunc(RecovRebootCallBacks, (ClientData)spriteID, 0);
  748.     }
  749. exit:
  750.     if (hostState == DEV_CLIENT_STATE_NEW_HOST) {
  751.     /*
  752.      * Only call into device module if this isn't a client we're
  753.      * doing server-driven recovery with at this very moment.
  754.      */
  755.     if ((hostPtr->clientState & CLT_DOING_SRV_RECOV) == 0) {
  756.         Dev_ClientHostUp(spriteID);
  757.     }
  758.     }
  759.     UNLOCK_MONITOR;
  760.     return;
  761. }
  762.  
  763. /*
  764.  *----------------------------------------------------------------------
  765.  *
  766.  * Recov_HostDead --
  767.  *
  768.  *    Change the host's state to "dead".  This is called from client RPC
  769.  *    when an RPC timed out with no response.  It is also called by the
  770.  *    Rpc_Daemon when it can't recontact a client to get an explicit
  771.  *    acknowledgment.
  772.  *
  773.  * Results:
  774.  *    None.
  775.  *
  776.  * Side effects:
  777.  *    If the host was previously thought up, this sets the state in
  778.  *    the host state table to dead and invokes the crash callbacks.
  779.  *
  780.  *----------------------------------------------------------------------
  781.  */
  782.  
  783. ENTRY void
  784. Recov_HostDead(spriteID)
  785.     int spriteID;
  786. {
  787.     register    Hash_Entry *hashPtr;
  788.     register    RecovHostState *hostPtr;
  789.     int        hostState = -1;
  790.  
  791.     LOCK_MONITOR;
  792.     if (spriteID == NET_BROADCAST_HOSTID || rpc_NoTimeouts) {
  793.     /*
  794.      * If rpcNoTimeouts is set the Rpc_Daemon may still call us if
  795.      * it can't get an acknowledgment from a host to close down
  796.      * a connection.  We ignore this so that we don't take action
  797.      * against the offending host (who is probably in the debugger)
  798.      * (Hmm, it doesn't look like Rpc_Daemon calls this procedure.)
  799.      */
  800.     UNLOCK_MONITOR;
  801.     return;
  802.     }
  803.  
  804.     recov_Stats.timeouts++;
  805.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  806.     if (hashPtr->value == (Address)NIL) {
  807.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_HOST_DEAD, 0);
  808.     hashPtr->value = (Address)hostPtr;
  809.     RECOV_TRACE(spriteID, RECOV_HOST_DEAD, RECOV_CUZ_INIT);
  810.     hostState = DEV_CLIENT_STATE_DEAD_HOST;
  811.     } else {
  812.     hostPtr = (RecovHostState *)hashPtr->value;
  813.     }
  814.     switch(hostPtr->state &
  815.         (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD)) {
  816.     case RECOV_HOST_DEAD:
  817.         /*
  818.          * Host already dead.
  819.          */
  820.         break;
  821.     case RECOV_STATE_UNKNOWN:
  822.     case RECOV_HOST_BOOTING:
  823.     case RECOV_HOST_ALIVE:
  824.         hostState = DEV_CLIENT_STATE_DEAD_HOST;
  825.         hostPtr->state &=
  826.         ~(RECOV_HOST_ALIVE|RECOV_HOST_BOOTING);
  827.         /*
  828.          * Special handling if we abort during the recovery protocol.
  829.          * In this case it is possible for the other host to go from
  830.          * alive to dead and back to alive before the recovery protocol
  831.          * finally terminates.  If that happens we could loose a reboot
  832.          * event and fail to initiate recovery again.  We mark the
  833.          * host specially so the reboot callbacks are retried.
  834.          */
  835.         if (hostPtr->state & RECOV_REBOOT_CALLBACKS) {
  836.         hostPtr->state |= RECOV_FAILURE;
  837.         }
  838.         hostPtr->state |= RECOV_HOST_DEAD|RECOV_CRASH_CALLBACKS;
  839.         RecovHostPrint(RECOV_PRINT_CRASH, spriteID,
  840.             "crash call-backs made\n");
  841.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH);
  842.         Proc_CallFunc(CrashCallBacks, (ClientData)spriteID, 0);
  843.         break;
  844.     }
  845.     if (hostState == DEV_CLIENT_STATE_DEAD_HOST) {
  846.     /*
  847.      * Only call into device module if this isn't a client we're
  848.      * doing server-driven recovery with at this very moment.
  849.      */
  850.     if ((hostPtr->clientState & CLT_DOING_SRV_RECOV) == 0) {
  851.         Dev_ClientHostDown(spriteID);
  852.     }
  853.     }
  854.     UNLOCK_MONITOR;
  855.     return;
  856. }
  857.  
  858. /*
  859.  *----------------------------------------------------------------------
  860.  *
  861.  * Recov_IsHostDown --
  862.  *
  863.  *    This decides if the specified host is down.  If the host is known
  864.  *    to be down this routine    returns FAILURE.  SUCCESS is returned if
  865.  *    the host is alive, and RPC_SERVICE_DISABLED is returned if the
  866.  *    host is in its boot sequence and can't service RPC's yet.  If there
  867.  *    hasn't been recent (within the last 10 seconds) message traffic
  868.  *    this this pings the host to find out for sure its state.
  869.  *
  870.  * Results:
  871.  *    SUCCESS if the host is up, FAILURE if it doesn't respond to
  872.  *    pings or is known to be down, and RPC_SERVICE_DISABLED if
  873.  *    the host says so.
  874.  *
  875.  * Side effects:
  876.  *    May do a ping.
  877.  *
  878.  *----------------------------------------------------------------------
  879.  */
  880.  
  881. ReturnStatus
  882. Recov_IsHostDown(spriteID)
  883.     int spriteID;
  884. {
  885.     register ReturnStatus status = SUCCESS;
  886.  
  887.     if (spriteID == NET_BROADCAST_HOSTID) {
  888.     printf("Warning: Recov_IsHostDown, got broadcast address\n");
  889.     return(SUCCESS);
  890.     }
  891.     switch (Recov_GetHostState(spriteID)) {
  892.     case RECOV_STATE_UNKNOWN:
  893.         RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_PING_ASK);
  894.         recov_Stats.pings++;
  895.         status = Rpc_Ping(spriteID);
  896.         break;
  897.     case RECOV_HOST_BOOTING:
  898.     case RECOV_HOST_ALIVE:     /* fake it to allow for the grace period */
  899.         recov_Stats.pingsSuppressed++;
  900.         status = SUCCESS;
  901.         break;
  902.     case RECOV_HOST_DEAD:
  903.         status = FAILURE;
  904.         break;
  905.     }
  906.     return(status);
  907. }
  908.  
  909. /*
  910.  *----------------------------------------------------------------------
  911.  *
  912.  * Recov_HostTrace --
  913.  *
  914.  *    Add an entry to the recovery trace.
  915.  *
  916.  * Results:
  917.  *    None.
  918.  *
  919.  * Side effects:
  920.  *    None.
  921.  *
  922.  *----------------------------------------------------------------------
  923.  */
  924.  
  925. ENTRY void
  926. Recov_HostTrace(spriteID, event)
  927.     int spriteID;
  928.     int event;
  929. {
  930.     /*
  931.      * No monitor lock needed here, since Trace_Insert does its own
  932.      * synchronization.
  933.      */
  934.     RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, event);
  935. }
  936.  
  937. /*
  938.  *----------------------------------------------------------------------
  939.  *
  940.  * Recov_GetClientState --
  941.  *
  942.  *    Return the client state associated with a host.  The recovery host
  943.  *    table is a convenient object keyed on spriteID.  Other modules can
  944.  *    set their own state in the table (beyond the simple up/down state
  945.  *    mainted by the rest of this module), and retrieve it with this call.
  946.  *
  947.  * Results:
  948.  *    A copy of the clientState field.  0 is returned if there is no
  949.  *    host table entry.
  950.  *
  951.  * Side effects:
  952.  *    None.
  953.  *
  954.  *----------------------------------------------------------------------
  955.  */
  956.  
  957. ENTRY int
  958. Recov_GetClientState(spriteID)
  959.     int spriteID;
  960. {
  961.     Hash_Entry *hashPtr;
  962.     RecovHostState *hostPtr;
  963.     int stateBits = 0;
  964.  
  965.     LOCK_MONITOR;
  966.  
  967.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  968.     if (hashPtr != (Hash_Entry *)NIL) {
  969.     hostPtr = (RecovHostState *)hashPtr->value;
  970.     if (hostPtr != (RecovHostState *)NIL) {
  971.         stateBits = hostPtr->clientState;
  972.     }
  973.     }
  974.     UNLOCK_MONITOR;
  975.     return(stateBits);
  976. }
  977.  
  978. /*
  979.  *----------------------------------------------------------------------
  980.  *
  981.  * Recov_SetClientState --
  982.  *
  983.  *    Set a client state bit.  This or's the parameter into the
  984.  *    client state word.  The previous value of the client state
  985.  *    word is returned so this procedure can be used like test-and-set.
  986.  *
  987.  * Results:
  988.  *    None.
  989.  *
  990.  * Side effects:
  991.  *    Sets bits in the clientState field of the host state.  This will add
  992.  *    an entry to the host table if one doesn't alreay exist.  Its RPC
  993.  *    up/down state is set to "unknown" in this case.
  994.  *
  995.  *----------------------------------------------------------------------
  996.  */
  997.  
  998. ENTRY int
  999. Recov_SetClientState(spriteID, stateBits)
  1000.     int spriteID;
  1001.     int stateBits;
  1002. {
  1003.     Hash_Entry *hashPtr;
  1004.     RecovHostState *hostPtr;
  1005.     register oldState;
  1006.     RecovStampList    *stampPtr;
  1007.  
  1008.  
  1009.     LOCK_MONITOR;
  1010.  
  1011.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  1012.     hostPtr = (RecovHostState *)hashPtr->value;
  1013.     if (hostPtr == (RecovHostState *)NIL) {
  1014.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  1015.     hashPtr->value = (Address)hostPtr;
  1016.     RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  1017.     }
  1018.     if ((stateBits & CLT_RECOV_IN_PROGRESS) != 0) {
  1019.     /*
  1020.      * This is a test to see if we get potential inconsistency from lacking
  1021.      * backwards compatibility with old kernels on clients and new server-
  1022.      * driven recovery.  It can go away when everybody is running a kernel
  1023.      * with the new recovery stuff in it.  - Mary 11/10/92.
  1024.      */
  1025.     if ((hostPtr->clientState & CLT_OLD_RECOV) && !recov_BlockingRpcs) {
  1026.         printf("Recov_SetClient: got late recovery from old client %d.\n",
  1027.             spriteID);
  1028.     }
  1029.  
  1030.     if (hostPtr->numTries == 0) {
  1031.         /* First recovery attempt */
  1032.         if ((hostPtr->clientState & CLT_RECOV_IN_PROGRESS) != 0) {
  1033.         printf("No recovery attempt yet, but marked as in progress.");
  1034.         }
  1035.         Timer_GetCurrentTicks(&hostPtr->start);
  1036.     } else {
  1037.         /* Add a time-stamp to the recovery list. */
  1038.         stampPtr = (RecovStampList *) malloc(sizeof (RecovStampList));
  1039.         Timer_GetCurrentTicks(&stampPtr->start);
  1040.         List_InitElement((List_Links *) stampPtr);
  1041.         List_Insert((List_Links *) stampPtr,
  1042.             LIST_ATREAR(&hostPtr->timeStampList));
  1043.         /*
  1044.          * Clear handle count for this round.
  1045.          */
  1046.         hostPtr->currentHandles = 0;
  1047.         hostPtr->currentSuccessful = 0;
  1048.     }
  1049.     hostPtr->numTries++;
  1050.     }
  1051.  
  1052.     oldState = hostPtr->clientState;
  1053.     hostPtr->clientState |= stateBits;
  1054.     UNLOCK_MONITOR;
  1055.     return(oldState);
  1056. }
  1057.  
  1058. /*
  1059.  *----------------------------------------------------------------------
  1060.  *
  1061.  * Recov_ClearClientState --
  1062.  *
  1063.  *    Clear client state bits.
  1064.  *
  1065.  * Results:
  1066.  *    None.
  1067.  *
  1068.  * Side effects:
  1069.  *    Clears bits in the clientState field of the host state.  This does
  1070.  *    nothing if the state doesn't exist.
  1071.  *
  1072.  *----------------------------------------------------------------------
  1073.  */
  1074.  
  1075. ENTRY void
  1076. Recov_ClearClientState(spriteID, stateBits)
  1077.     int spriteID;
  1078.     int stateBits;
  1079. {
  1080.     register Hash_Entry        *hashPtr;
  1081.     register RecovHostState    *hostPtr = (RecovHostState *) NIL;
  1082.     RecovStampList        *stampPtr;
  1083.  
  1084.     LOCK_MONITOR;
  1085.  
  1086.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1087.     if (hashPtr != (Hash_Entry *)NIL) {
  1088.     hostPtr = (RecovHostState *)hashPtr->value;
  1089.     if (hostPtr != (RecovHostState *)NIL) {
  1090.         hostPtr->clientState &= ~stateBits;
  1091.     }
  1092.     }
  1093.     /* End of recovery? */
  1094.     if ((hostPtr != (RecovHostState *) NIL) &&
  1095.         (stateBits & CLT_RECOV_IN_PROGRESS) != 0) {
  1096.     /* End of 1st recovery try? */
  1097.     if (hostPtr->numTries <= 1) {
  1098.         Timer_GetCurrentTicks(&hostPtr->finished);
  1099.         /* Final count of handles recovered is in hostPtr. */
  1100.         hostPtr->numHandles = hostPtr->currentHandles;
  1101.         hostPtr->numSuccessful = hostPtr->currentSuccessful;
  1102.     } else {
  1103.         if (List_IsEmpty(&hostPtr->timeStampList)) {
  1104.         printf("Recov_ClearClientState: timeStampList is empty!\n");
  1105.         hostPtr->numSuccessful = 0;    /* signal the error */
  1106.         } else {
  1107.         stampPtr = (RecovStampList *)
  1108.             List_Last((List_Links *) &hostPtr->timeStampList);
  1109.         Timer_GetCurrentTicks(&stampPtr->finished);
  1110.         stampPtr->numHandles = hostPtr->currentHandles;
  1111.         stampPtr->numSuccessful = hostPtr->currentSuccessful;
  1112.         }
  1113.     }
  1114.     }
  1115.     UNLOCK_MONITOR;
  1116.     return;
  1117. }
  1118.  
  1119.  
  1120. /*
  1121.  *----------------------------------------------------------------------
  1122.  *
  1123.  * Recov_AddHandleCountToClientState --
  1124.  *
  1125.  *    Increment count of handles reopened from this client.
  1126.  *
  1127.  * Results:
  1128.  *    None.
  1129.  *
  1130.  * Side effects:
  1131.  *    Data in per-host recovery info updated.
  1132.  *
  1133.  *----------------------------------------------------------------------
  1134.  */
  1135. ENTRY void
  1136. Recov_AddHandleCountToClientState(type, clientID, status)
  1137.     int            type;        /* Type of handle being reopened. */
  1138.     int            clientID;    /* Id of client requesting reopen. */
  1139.     ReturnStatus    status;        /* Whether the reopen succeeded. */
  1140. {
  1141.     register Hash_Entry *hashPtr;
  1142.     register RecovHostState *hostPtr = (RecovHostState *) NIL;
  1143.  
  1144.     LOCK_MONITOR;
  1145.  
  1146.     hashPtr = Hash_LookOnly(recovHashTable, (Address)clientID);
  1147.     if (hashPtr != (Hash_Entry *)NIL) {
  1148.     hostPtr = (RecovHostState *)hashPtr->value;
  1149.     if (hostPtr != (RecovHostState *)NIL) {
  1150.         hostPtr->currentHandles++;
  1151.         if (status == SUCCESS) {
  1152.         hostPtr->currentSuccessful++;
  1153.         }
  1154.     }
  1155.     }
  1156.     UNLOCK_MONITOR;
  1157.     return;
  1158. }
  1159.  
  1160.  
  1161. /*
  1162.  *----------------------------------------------------------------------
  1163.  *
  1164.  * Recov_DumpClientRecovInfo --
  1165.  *
  1166.  *    Dump out some of the recovery statistics in the per-host info.
  1167.  *
  1168.  * Results:
  1169.  *    Returns FAILURE if recovery still in progress.  Returns SUCCESS
  1170.  *    otherwise.
  1171.  *
  1172.  * Side effects:
  1173.  *    Info copied into buffer.  Size of needed buffer also copied out.
  1174.  *
  1175.  *----------------------------------------------------------------------
  1176.  */
  1177. ENTRY ReturnStatus
  1178. Recov_DumpClientRecovInfo(length, resultPtr, lengthNeededPtr)
  1179.     int            length;            /* size of data buffer */
  1180.     Address        resultPtr;        /* Array of info structs. */
  1181.     int            *lengthNeededPtr;    /* to return space needed */
  1182. {
  1183.     Hash_Entry        *hashPtr;
  1184.     RecovHostState    *hostPtr;
  1185.     Hash_Search        hashSearch;
  1186.     RecovPerHostInfo    *infoPtr;
  1187.     int            numNeeded;
  1188.     int            numAvail;
  1189.  
  1190.     LOCK_MONITOR;
  1191.  
  1192.     /*
  1193.      * If recovery still going on, return FAILURE.
  1194.      * NOTE: This isn't a sure-fire test.  I'm not sure there is one right now.
  1195.      */
  1196.     if (fsutil_NumRecovering >= 1) {
  1197.     UNLOCK_MONITOR;
  1198.     return FAILURE;
  1199.     }
  1200.     if (resultPtr != (Address) NIL) {
  1201.     bzero(resultPtr, length);
  1202.     }
  1203.     numNeeded = 0;
  1204.     numAvail = length / sizeof (RecovPerHostInfo);
  1205.  
  1206.     infoPtr = (RecovPerHostInfo *) resultPtr;
  1207.     Hash_StartSearch(&hashSearch);
  1208.     for (hashPtr = Hash_Next(recovHashTable, &hashSearch);
  1209.         hashPtr != (Hash_Entry *) NIL;
  1210.         hashPtr = Hash_Next(recovHashTable, &hashSearch)) {
  1211.     hostPtr = (RecovHostState *)hashPtr->value;
  1212.  
  1213.     /*
  1214.      * We need one slot for each host, whether numTries is 0 or 1, plus
  1215.      * additional slots for each numTries over 1.
  1216.      */
  1217.     numNeeded++;
  1218.     if (hostPtr->numTries > 1) {
  1219.         numNeeded += (hostPtr->numTries - 1);
  1220.     }
  1221.     if (numNeeded > numAvail) {
  1222.         continue;
  1223.     }
  1224.     /* Why didn't Brent use GetValue()??? */
  1225.     if (hostPtr != (RecovHostState *) NIL) {
  1226.         RecovStampList    *stampPtr;
  1227.  
  1228.         /* Copy info into buffer */
  1229.         infoPtr->spriteID = hostPtr->spriteID;
  1230.         infoPtr->numTries = hostPtr->numTries;
  1231.         Timer_GetRealTimeFromTicks(hostPtr->start,
  1232.             &(infoPtr->start), (int *) NIL, (Boolean *) NIL);
  1233.         Timer_GetRealTimeFromTicks(hostPtr->finished,
  1234.             &(infoPtr->finished), (int *)NIL, (Boolean *) NIL);
  1235.         infoPtr->numHandles = hostPtr->numHandles;
  1236.         infoPtr->numSuccessful = hostPtr->numSuccessful;
  1237.         LIST_FORALL(&hostPtr->timeStampList, (List_Links *) stampPtr) {
  1238.         infoPtr++;
  1239.         Timer_GetRealTimeFromTicks(stampPtr->start,
  1240.             &infoPtr->start, (int *) NIL, (Boolean *) NIL);
  1241.         Timer_GetRealTimeFromTicks(stampPtr->finished,
  1242.             &infoPtr->finished, (int *) NIL, (Boolean *) NIL);
  1243.         infoPtr->numHandles = stampPtr->numHandles;
  1244.         infoPtr->numSuccessful = stampPtr->numSuccessful;
  1245.         }
  1246.     }
  1247.     infoPtr++;
  1248.     }
  1249.     *lengthNeededPtr = numNeeded * sizeof (RecovPerHostInfo);
  1250.     UNLOCK_MONITOR;
  1251.  
  1252.     return SUCCESS;
  1253. }
  1254.  
  1255. /*
  1256.  *----------------------------------------------------------------------
  1257.  *
  1258.  * RecovRebootCallBacks --
  1259.  *
  1260.  *    This calls the call-back procedures installed by other modules
  1261.  *    via Recov_RebootRegister.  It is invoked asynchronously from
  1262.  *    Recov_HostAlive when that procedure detects a reboot.
  1263.  *
  1264.  * Results:
  1265.  *    None.
  1266.  *
  1267.  * Side effects:
  1268.  *    Invoke the call-backs.
  1269.  *
  1270.  *----------------------------------------------------------------------
  1271.  */
  1272. /*ARGSUSED*/
  1273. void
  1274. RecovRebootCallBacks(data, callInfoPtr)
  1275.     ClientData data;
  1276.     Proc_CallInfo *callInfoPtr;
  1277. {
  1278.     List_Links notifyList;
  1279.     register NotifyElement *notifyPtr;
  1280.     register int spriteID = (int)data;
  1281.  
  1282. printf("RecovRebootCallBacks called for %d\n", spriteID);
  1283.     GetRebootList(¬ifyList, spriteID);
  1284.     RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_DOING_CALLBACKS);
  1285.     recov_Stats.reboots++;
  1286.     while (!List_IsEmpty(¬ifyList)) {
  1287.     notifyPtr = (NotifyElement *)List_First(¬ifyList);
  1288.     (*notifyPtr->proc)(spriteID, notifyPtr->data);
  1289.     List_Remove((List_Links *)notifyPtr);
  1290.     free((Address)notifyPtr);
  1291.     }
  1292.     CallBacksDone(spriteID);
  1293.     return;
  1294. }
  1295.  
  1296. /*
  1297.  *----------------------------------------------------------------------
  1298.  *
  1299.  * GetRebootList --
  1300.  *
  1301.  *    Copy out the list of reboot callbacks.  The list is protected by
  1302.  *     a monitor, but we don't want to call any recovery procedures from
  1303.  *    inside that monitor so we make a copy.
  1304.  *
  1305.  * Results:
  1306.  *    None.
  1307.  *
  1308.  * Side effects:
  1309.  *    Copy the reboot list off the host state table and return it
  1310.  *    to our caller who should free up the copied elements.
  1311.  *
  1312.  *----------------------------------------------------------------------
  1313.  */
  1314.  
  1315. ENTRY static void
  1316. GetRebootList(notifyListHdr, spriteID)
  1317.     List_Links *notifyListHdr;
  1318.     int spriteID;
  1319. {
  1320.     register Hash_Entry *hashPtr;
  1321.     register RecovHostState *hostPtr;
  1322.     register NotifyElement *notifyPtr;
  1323.     register NotifyElement *newNotifyPtr;
  1324.  
  1325.     LOCK_MONITOR;
  1326.  
  1327.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1328.     hostPtr = (RecovHostState *)hashPtr->value;
  1329.     List_Init(notifyListHdr);
  1330.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  1331.     newNotifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  1332.     newNotifyPtr->proc = notifyPtr->proc;
  1333.     newNotifyPtr->data = notifyPtr->data;
  1334.     List_InitElement((List_Links *)newNotifyPtr);
  1335.     List_Insert((List_Links *)newNotifyPtr, LIST_ATREAR(notifyListHdr));
  1336.     }
  1337.     UNLOCK_MONITOR;
  1338.     return;
  1339. }
  1340.  
  1341. /*
  1342.  *----------------------------------------------------------------------
  1343.  *
  1344.  * CallBacksDone --
  1345.  *
  1346.  *    Clear the internal state bit that says callbacks are in progress.
  1347.  *    This checks to see if there was a communication failure during
  1348.  *    the reboot callbacks.  If so, the WANT_RECOVERY bit is set
  1349.  *    to ensure that another set of reboot callbacks are made.
  1350.  *
  1351.  * Results:
  1352.  *    None.
  1353.  *
  1354.  * Side effects:
  1355.  *    Clears RECOV_REBOOT_CALLBACKS and RECOV_FAILURE.  May set
  1356.  *    RECOV_WANT_RECOVERY if RECOV_FAILURE was set.
  1357.  *
  1358.  *----------------------------------------------------------------------
  1359.  */
  1360.  
  1361. ENTRY static void
  1362. CallBacksDone(spriteID)
  1363.     int spriteID;
  1364. {
  1365.     register Hash_Entry *hashPtr;
  1366.     register RecovHostState *hostPtr;
  1367.  
  1368.     LOCK_MONITOR;
  1369.  
  1370.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1371.     hostPtr = (RecovHostState *)hashPtr->value;
  1372.     hostPtr->state &= ~RECOV_REBOOT_CALLBACKS;
  1373.     RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_DONE_CALLBACKS);
  1374.     if (hostPtr->state & (RECOV_FAILURE)) {
  1375.     /*
  1376.      * There has been a communication failure during the reboot callbacks.
  1377.      */
  1378.     hostPtr->numFailures++;
  1379.     hostPtr->state &= ~RECOV_FAILURE;
  1380.     hostPtr->state |= RECOV_WANT_RECOVERY;
  1381.     RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_FAILURE);
  1382.     } else {
  1383.     hostPtr->numFailures = 0;
  1384.     }
  1385.     UNLOCK_MONITOR;
  1386.     return;
  1387. }
  1388.  
  1389. /*
  1390.  *----------------------------------------------------------------------
  1391.  *
  1392.  * CrashCallBacks --
  1393.  *
  1394.  *    Invoked asynchronously so that other modules
  1395.  *    can clean up behind the crashed host.  When done the host
  1396.  *    is marked as having recovery complete.  This unblocks server
  1397.  *    processes stalled in Recov_HostAlive.
  1398.  *
  1399.  * Results:
  1400.  *    None.
  1401.  *
  1402.  * Side effects:
  1403.  *    Invoke the crash call-backs.
  1404.  *    Clears the recovery in progress flag checked in Recov_HostAlive.
  1405.  *
  1406.  *----------------------------------------------------------------------
  1407.  */
  1408.  
  1409. static void
  1410. CrashCallBacks(data, callInfoPtr)
  1411.     ClientData data;
  1412.     Proc_CallInfo *callInfoPtr;
  1413. {
  1414.     register NotifyElement *notifyPtr;
  1415.     register int spriteID = (int)data;
  1416.  
  1417.     recov_Stats.crashes++;
  1418.     LIST_FORALL(&crashCallBackList, (List_Links *)notifyPtr) {
  1419.     if (notifyPtr->proc != (void (*)())NIL) {
  1420.         (*notifyPtr->proc)(spriteID, notifyPtr->data);
  1421.      }
  1422.     }
  1423.     MarkRecoveryComplete(spriteID);
  1424.     RECOV_TRACE(spriteID, RECOV_CRASH, RECOV_CUZ_DONE);
  1425.     callInfoPtr->interval = 0;    /* Don't call again */
  1426.     return;
  1427. }
  1428.  
  1429. /*
  1430.  *----------------------------------------------------------------------
  1431.  *
  1432.  * MarkRecoveryComplete --
  1433.  *
  1434.  *    The recovery call-backs have completed, and this procedure's
  1435.  *    job is to mark that fact in the host hash table and to notify
  1436.  *    any processes that are blocked in Recov_HostAlive waiting for this.
  1437.  *
  1438.  * Results:
  1439.  *    None.
  1440.  *
  1441.  * Side effects:
  1442.  *    Sets the state, if any, in the host state table.
  1443.  *    Notifies the hostPtr->recovery condition
  1444.  *
  1445.  *----------------------------------------------------------------------
  1446.  */
  1447.  
  1448. ENTRY static void
  1449. MarkRecoveryComplete(spriteID)
  1450.     int    spriteID;
  1451. {
  1452.     register Hash_Entry *hashPtr;
  1453.     register RecovHostState *hostPtr;
  1454.  
  1455.     LOCK_MONITOR;
  1456.  
  1457.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1458.     if (hashPtr != (Hash_Entry *)NIL) {
  1459.     hostPtr = (RecovHostState *)hashPtr->value;
  1460.     if (hostPtr != (RecovHostState *)NIL) {
  1461.         hostPtr->state &= ~RECOV_CRASH_CALLBACKS;
  1462.         Sync_Broadcast(&hostPtr->recovery);
  1463.     }
  1464.     }
  1465.     UNLOCK_MONITOR;
  1466.     return;
  1467. }
  1468.  
  1469. /*
  1470.  *----------------------------------------------------------------------
  1471.  *
  1472.  * Recov_GetHostState --
  1473.  *
  1474.  *    This looks into    the host table to see and provides a guess
  1475.  *    as to the host's current state.  It uses a timestamp kept in
  1476.  *    the host state to see if there's been recent message traffic.
  1477.  *    If so, RECOV_HOST_ALIVE is returned.  If not, RECOV_STATE_UNKNOWN
  1478.  *    is returned and the caller should ping to make sure.  Finally,
  1479.  *    if it is known that the host is down already, then RECOV_HOST_DEAD
  1480.  *    is returned.
  1481.  *
  1482.  * Results:
  1483.  *    RECOV_STATE_UNKNOWN if the caller should ping to make sure.
  1484.  *    RECOV_HOST_ALIVE if the host is up (recent message traffic).
  1485.  *    RECOV_HOST_DEAD if the host is down (recent timeouts).
  1486.  *
  1487.  * Side effects:
  1488.  *    None.
  1489.  *
  1490.  *----------------------------------------------------------------------
  1491.  */
  1492.  
  1493. ENTRY int
  1494. Recov_GetHostState(spriteID)
  1495.     int spriteID;
  1496. {
  1497.     register Hash_Entry *hashPtr;
  1498.     register RecovHostState *hostPtr;
  1499.     register int state = RECOV_STATE_UNKNOWN;
  1500.     Time time;
  1501.  
  1502.     LOCK_MONITOR;
  1503.  
  1504.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1505.     if (hashPtr != (Hash_Entry *)NIL) {
  1506.     hostPtr = (RecovHostState *)hashPtr->value;
  1507.     if (hostPtr != (RecovHostState *)NIL) {
  1508.         state = hostPtr->state &
  1509.      (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD);
  1510.         if (state & (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING)) {
  1511.         /*
  1512.          * Check for recent message traffic before admitting
  1513.          * that the other machine is up.
  1514.          */
  1515.         Timer_GetTimeOfDay(&time, (int *)NIL, (Boolean *)NIL);
  1516.         Time_Subtract(time, hostPtr->time, &time);
  1517.         if (Time_GT(time, time_TenSeconds)) {
  1518.             state = RECOV_STATE_UNKNOWN;
  1519.         }
  1520.         }
  1521.     }
  1522.     }
  1523.     UNLOCK_MONITOR;
  1524.     return(state);
  1525. }
  1526.  
  1527. /*
  1528.  *----------------------------------------------------------------------
  1529.  *
  1530.  * Recov_GetHostOldState --
  1531.  *
  1532.  *    This looks into    the host table to see what was the host's old
  1533.  *    state the last time it was pinged.
  1534.  *
  1535.  * Results:
  1536.  *    RECOV_STATE_UNKNOWN if unsure.
  1537.  *    RECOV_HOST_ALIVE if the host was up (recent message traffic).
  1538.  *    RECOV_HOST_DEAD if the host was down (recent timeouts).
  1539.  *
  1540.  * Side effects:
  1541.  *    None.
  1542.  *
  1543.  *----------------------------------------------------------------------
  1544.  */
  1545.  
  1546. ENTRY int
  1547. Recov_GetHostOldState(spriteID)
  1548.     int spriteID;
  1549. {
  1550.     register Hash_Entry *hashPtr;
  1551.     register RecovHostState *hostPtr;
  1552.     register int oldState = RECOV_STATE_UNKNOWN;
  1553.  
  1554.     LOCK_MONITOR;
  1555.  
  1556.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1557.     if (hashPtr != (Hash_Entry *)NIL) {
  1558.     hostPtr = (RecovHostState *)hashPtr->value;
  1559.     if (hostPtr != (RecovHostState *)NIL) {
  1560.         oldState = hostPtr->oldState &
  1561.      (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD);
  1562.     }
  1563.     }
  1564.     UNLOCK_MONITOR;
  1565.     return(oldState);
  1566. }
  1567.  
  1568. /*
  1569.  *----------------------------------------------------------------------
  1570.  *
  1571.  * Recov_SetHostOldState --
  1572.  *
  1573.  *    This sets the oldState of the host to what it was when pinged
  1574.  *    this time, for reference the next time it's pinged.
  1575.  *
  1576.  * Results:
  1577.  *    None.
  1578.  *
  1579.  * Side effects:
  1580.  *    Sets oldState in host info.
  1581.  *
  1582.  *----------------------------------------------------------------------
  1583.  */
  1584.  
  1585. ENTRY void
  1586. Recov_SetHostOldState(spriteID, state)
  1587.     int spriteID;
  1588.     int    state;
  1589. {
  1590.     register Hash_Entry *hashPtr;
  1591.     register RecovHostState *hostPtr;
  1592.  
  1593.     LOCK_MONITOR;
  1594.  
  1595.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1596.     if (hashPtr != (Hash_Entry *)NIL) {
  1597.     hostPtr = (RecovHostState *)hashPtr->value;
  1598.     if (hostPtr != (RecovHostState *)NIL) {
  1599.         hostPtr->oldState = state;
  1600.     }
  1601.     }
  1602.     UNLOCK_MONITOR;
  1603.     return;
  1604. }
  1605.  
  1606. /*
  1607.  *----------------------------------------------------------------------
  1608.  *
  1609.  * RecovGetLastHostState --
  1610.  *
  1611.  *    This looks into    the host table to pass back the
  1612.  *    host's current state.  It just uses whatever state the
  1613.  *    host has marked currently, and does no further interpretation.
  1614.  *
  1615.  * Results:
  1616.  *    hostPtr->state
  1617.  *
  1618.  * Side effects:
  1619.  *    None.
  1620.  *
  1621.  *----------------------------------------------------------------------
  1622.  */
  1623.  
  1624. ENTRY int
  1625. RecovGetLastHostState(spriteID)
  1626.     int spriteID;
  1627. {
  1628.     register Hash_Entry *hashPtr;
  1629.     register RecovHostState *hostPtr;
  1630.     register int state = RECOV_STATE_UNKNOWN;
  1631.  
  1632.     LOCK_MONITOR;
  1633.  
  1634.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1635.     if (hashPtr != (Hash_Entry *)NIL) {
  1636.     hostPtr = (RecovHostState *)hashPtr->value;
  1637.     if (hostPtr != (RecovHostState *)NIL) {
  1638.         state = hostPtr->state;
  1639.     }
  1640.     }
  1641.     UNLOCK_MONITOR;
  1642.     return(state);
  1643. }
  1644.  
  1645. /*
  1646.  *----------------------------------------------------------------------
  1647.  *
  1648.  * RecovCheckHost --
  1649.  *
  1650.  *    This decides if we should check up on a host.  If there has
  1651.  *    been recent message traffic there is no need to ping now,
  1652.  *    but we should check again later.  If there has been no
  1653.  *    message traffic our caller should ping.  Finally, if
  1654.  *    there are no reboot callbacks associated with the host,
  1655.  *    then we are not interested anymore.  Thus there are three
  1656.  *    values to return.
  1657.  *
  1658.  * Results:
  1659.  *    -1 if we are no longer interested in the host.
  1660.  *    0 if the host is presumably up and we don't have to ping.
  1661.  *    1 if our caller should ping.
  1662.  *
  1663.  * Side effects:
  1664.  *    None.
  1665.  *
  1666.  *----------------------------------------------------------------------
  1667.  */
  1668.  
  1669. ENTRY int
  1670. RecovCheckHost(spriteID)
  1671.     int    spriteID;
  1672. {
  1673.     register Hash_Entry *hashPtr;
  1674.     register RecovHostState *hostPtr = (RecovHostState *)NIL;
  1675.     register int check = -1;    /* forget about the host */
  1676.     register int state;
  1677.  
  1678.     LOCK_MONITOR;
  1679.  
  1680.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1681.     if (hashPtr != (Hash_Entry *)NIL) {
  1682.     hostPtr = (RecovHostState *)hashPtr->value;
  1683.     if ((hostPtr != (RecovHostState *)NIL) &&
  1684.         (!List_IsEmpty(&hostPtr->rebootList))) {
  1685.         state = hostPtr->state &
  1686.      (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD);
  1687.         if (state & (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING)) {
  1688.         /*
  1689.          * Check for recent message traffic before admitting
  1690.          * that the other machine is up.
  1691.          */
  1692.         Time time;
  1693.         Timer_GetTimeOfDay(&time, (int *)NIL, (Boolean *)NIL);
  1694.         Time_Subtract(time, hostPtr->time, &time);
  1695.         if (Time_GT(time, time_TenSeconds)) {
  1696.             check = 1;    /* ping the host now */
  1697.         } else {
  1698.             check = 0;    /* ping the host maybe next time */
  1699.         }
  1700.         } else if (state & RECOV_HOST_DEAD) {
  1701.         check = 1;    /* ping the host now */
  1702.         }
  1703.     }
  1704.     }
  1705.     if (check < 0 && hostPtr != (RecovHostState *)NIL) {
  1706.     hostPtr->state &= ~RECOV_PINGING_HOST;
  1707.     }
  1708.     UNLOCK_MONITOR;
  1709.     return(check);
  1710. }
  1711.  
  1712. /*
  1713.  *----------------------------------------------------------------------
  1714.  *
  1715.  * Recov_GetStats --
  1716.  *
  1717.  *    Return the Recov_Stats to user-level, and perhaps more information
  1718.  *    about our internal opinion of other hosts.
  1719.  *
  1720.  * Results:
  1721.  *    None.
  1722.  *
  1723.  * Side effects:
  1724.  *    Copies data out to user-space.
  1725.  *
  1726.  *----------------------------------------------------------------------
  1727.  */
  1728. ReturnStatus
  1729. Recov_GetStats(size, userAddr)
  1730.     int size;
  1731.     Address userAddr;
  1732. {
  1733.     ReturnStatus status;
  1734. #ifdef notdef    
  1735.     int extraSpace = -1;
  1736. #endif
  1737.     if (size <= 0) {
  1738.     return(GEN_INVALID_ARG);
  1739.     }
  1740.     /*
  1741.      * See if the caller wants more than just statistics.
  1742.      */
  1743.     if (size > sizeof(Recov_Stats)) {
  1744. #ifdef notdef    
  1745.     extraSpace = size - sizeof(Recov_Stats);
  1746. #endif    
  1747.     size = sizeof(Recov_Stats);
  1748.     }
  1749.     status = Vm_CopyOut(size, (Address)&recov_Stats, userAddr);
  1750.  
  1751. #ifdef notdef
  1752.     if (extraSpace > sizeof(int)) {
  1753.     /*
  1754.      * Fill the user-space buffer with a count of hosts,
  1755.      * and then information about each host.
  1756.      */
  1757.     userAddr += sizeof(Recov_Stats);
  1758.     status = Recov_DumpState(extraSpace, userAddr);
  1759.     }
  1760. #endif notdef
  1761.     return(status);
  1762. }
  1763.  
  1764. /*
  1765.  *----------------------------------------------------------------------
  1766.  *
  1767.  * Recov_DumpState --
  1768.  *
  1769.  *    Dump internal state to user-level.
  1770.  *
  1771.  * Results:
  1772.  *    None.
  1773.  *
  1774.  * Side effects:
  1775.  *    Copies data out to user-space.
  1776.  *
  1777.  *----------------------------------------------------------------------
  1778.  */
  1779. ReturnStatus
  1780. Recov_DumpState(size, userAddr)
  1781.     int size;
  1782.     Address userAddr;
  1783. {
  1784.     ReturnStatus status = SUCCESS;
  1785.     int numHosts, maxHosts;
  1786.     int *countPtr;
  1787.     int spriteID;
  1788.     Recov_State recovState;
  1789.  
  1790.     /*
  1791.      * We return a count, plus count number of Recov_State structures.
  1792.      */
  1793.     maxHosts = (size - sizeof(int)) / sizeof(Recov_State);
  1794.     countPtr = (int *)userAddr;
  1795.     if ((maxHosts == 0) && (size > sizeof(int))) {
  1796.     status = Vm_CopyOut(sizeof(int), (Address)&maxHosts, (Address)countPtr);
  1797.     return(status);
  1798.     }
  1799.      userAddr += sizeof(int);
  1800.     /*
  1801.      * Brute force.  Run through til MAX_HOSTS and try to grab
  1802.      * the state from the hash table.
  1803.      */
  1804.     numHosts = 0;
  1805.     for (spriteID = 1 ; spriteID < NET_NUM_SPRITE_HOSTS ; spriteID++) {
  1806.     if (Recov_GetHostInfo(spriteID, &recovState)) {
  1807.         status = Vm_CopyOut(sizeof(recovState), (Address)&recovState,
  1808.                 userAddr);
  1809.         if (status != SUCCESS) {
  1810.         return(status);
  1811.         }
  1812.         userAddr += sizeof(recovState);
  1813.         numHosts++;
  1814.         if (numHosts >= maxHosts) {
  1815.         break;
  1816.         }
  1817.     }
  1818.     }
  1819.  
  1820.     return(status);
  1821. }
  1822.  
  1823. /*
  1824.  *----------------------------------------------------------------------
  1825.  *
  1826.  * Recov_GetHostInfo --
  1827.  *
  1828.  *    Get the internal state about a host.
  1829.  *
  1830.  * Results:
  1831.  *    Fills in a Recov_State structure and returns TRUE,
  1832.  *    otherwise, if we don't know about the host, returns FALSE
  1833.  *
  1834.  * Side effects:
  1835.  *    None.
  1836.  *
  1837.  *----------------------------------------------------------------------
  1838.  */
  1839.  
  1840. ENTRY Boolean
  1841. Recov_GetHostInfo(spriteID, recovStatePtr)
  1842.     int spriteID;
  1843.     Recov_State *recovStatePtr;
  1844. {
  1845.     Hash_Entry *hashPtr;
  1846.     RecovHostState *hostPtr;
  1847.     Boolean found = FALSE;
  1848.  
  1849.     LOCK_MONITOR;
  1850.  
  1851.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  1852.     goto exit;
  1853.     } else {
  1854.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1855.     if (hashPtr == (Hash_Entry *)NULL || hashPtr->value == (Address)NIL) {
  1856.         goto exit;
  1857.     } else {
  1858.         hostPtr = (RecovHostState *)hashPtr->value;
  1859.     }
  1860.     recovStatePtr->spriteID = spriteID;
  1861.     recovStatePtr->state = hostPtr->state;
  1862.     recovStatePtr->clientState = hostPtr->clientState;
  1863.     recovStatePtr->bootID = hostPtr->bootID;
  1864.     recovStatePtr->time = hostPtr->time;
  1865.     found = TRUE;
  1866.     }
  1867. exit:
  1868.     UNLOCK_MONITOR;
  1869.     return(found);
  1870. }
  1871.  
  1872.  
  1873. /*
  1874.  *----------------------------------------------------------------------
  1875.  *
  1876.  * Recov_PrintTraceRecord --
  1877.  *
  1878.  *    Format and print the client data part of a recovery trace record.
  1879.  *
  1880.  * Results:
  1881.  *    None.
  1882.  *
  1883.  * Side effects:
  1884.  *    printf to the display.
  1885.  *
  1886.  *----------------------------------------------------------------------
  1887.  */
  1888. int
  1889. Recov_PrintTraceRecord(clientData, event, printHeaderFlag)
  1890.     ClientData clientData;    /* Client data in the trace record */
  1891.     int event;            /* Type, or event, from the trace record */
  1892.     Boolean printHeaderFlag;    /* If TRUE, a header line is printed */
  1893. {
  1894.     RecovTraceRecord *recPtr = (RecovTraceRecord *)clientData;
  1895.     char name[128];
  1896.     if (printHeaderFlag) {
  1897.     /*
  1898.      * Print column headers and a newline.
  1899.      */
  1900.     printf("%10s %10s %17s\n", "Host", "State", "Event ");
  1901.     }
  1902.     if (clientData != (ClientData)NIL) {
  1903.     Net_SpriteIDToName(recPtr->spriteID, 128, name);
  1904.     if (*name == '\0') {
  1905.         printf("%10d ", recPtr->spriteID);
  1906.     } else {
  1907.         printf("%10s ", name);
  1908.     }
  1909.     printf("%-8s", GetState(recPtr->state));
  1910.     printf("%3s", (recPtr->state & RECOV_CRASH_CALLBACKS) ?
  1911.                 " C " : "   ");
  1912.     printf("%3s", (recPtr->state & RECOV_PINGING_HOST) ?
  1913.                 " P " : "   ");
  1914.     printf("%3s", (recPtr->state & RECOV_REBOOT_CALLBACKS) ?
  1915.                 " R " : "   ");
  1916.     printf("%3s", (recPtr->state & RECOV_WANT_RECOVERY) ?
  1917.                 " W " : "   ");
  1918.     printf("%3s", (recPtr->state & RECOV_FAILURE) ?
  1919.                 " F " : "   ");
  1920.     switch(event) {
  1921.         case RECOV_CUZ_WAIT:
  1922.         printf("waiting");
  1923.         break;
  1924.         case RECOV_CUZ_WAKEUP:
  1925.         printf("wakeup");
  1926.         break;
  1927.         case RECOV_CUZ_INIT:
  1928.         printf("init");
  1929.         break;
  1930.         case RECOV_CUZ_REBOOT:
  1931.         printf("reboot");
  1932.         break;
  1933.         case RECOV_CUZ_CRASH:
  1934.         printf("crash");
  1935.         break;
  1936.         case RECOV_CUZ_CRASH_UNDETECTED:
  1937.         printf("crash undetected");
  1938.         break;
  1939.         case RECOV_CUZ_DONE:
  1940.         printf("done");
  1941.         break;
  1942.         case RECOV_CUZ_PING_ASK:
  1943.         printf("ping (ask)");
  1944.         break;
  1945.         case RECOV_CUZ_PING_CHK:
  1946.         printf("ping (check)");
  1947.         break;
  1948.         case RECOV_TRACE_FS_STALE:
  1949.         printf("stale FS handle");
  1950.         break;
  1951.         case RECOV_CUZ_SCHED_CALLBACK:
  1952.         printf("scheduled callback");
  1953.         break;
  1954.         case RECOV_CUZ_DONE_CALLBACKS:
  1955.         printf("done callbacks");
  1956.         break;
  1957.         case RECOV_CUZ_FAILURE:
  1958.         printf("failure during callbacks");
  1959.         break;
  1960.         case RECOV_CUZ_WAS_BOOTING:
  1961.         printf("was booting");
  1962.         break;
  1963.         case RECOV_CUZ_NOW_BOOTING:
  1964.         printf("now booting");
  1965.         break;
  1966.         case RECOV_CUZ_WAS_DEAD:
  1967.         printf("was dead");
  1968.         break;
  1969.         case RECOV_CUZ_DOING_CALLBACKS:
  1970.         printf("doing callbacks");
  1971.         break;
  1972.         case RECOV_CUZ_START:
  1973.         printf("start-up");
  1974.         break;
  1975.         default:
  1976.         printf("(%x)", event);
  1977.         break;
  1978.     }
  1979.     /* Our caller prints a newline */
  1980.     }
  1981.     return 0;
  1982. }
  1983.  
  1984. /*
  1985.  *----------------------------------------------------------------------
  1986.  *
  1987.  * Recov_PrintTrace --
  1988.  *
  1989.  *    Dump out the recovery trace.  Called via a console L1 keystroke.
  1990.  *
  1991.  * Results:
  1992.  *    None.
  1993.  *
  1994.  * Side effects:
  1995.  *    Prints to the console.
  1996.  *
  1997.  *----------------------------------------------------------------------
  1998.  */
  1999.  
  2000. void
  2001. Recov_PrintTrace(clientData)
  2002.     ClientData clientData;
  2003. {
  2004.     int numRecs = (int)clientData;
  2005.  
  2006.     if (numRecs <= 0 || numRecs > recovTraceLength) {
  2007.     numRecs = recovTraceLength;
  2008.     }
  2009.     printf("RECOVERY TRACE\n");
  2010.     (void)Trace_Print(recovTraceHdrPtr, numRecs, Recov_PrintTraceRecord);
  2011.     Recov_PrintState();
  2012.     RecovPrintPingList();
  2013.     return;
  2014. }
  2015.  
  2016. /*
  2017.  *----------------------------------------------------------------------
  2018.  *
  2019.  * Recov_PrintState --
  2020.  *
  2021.  *    Dump out the recovery state.  Called via a console L1 keystroke.
  2022.  *
  2023.  * Results:
  2024.  *    None.
  2025.  *
  2026.  * Side effects:
  2027.  *    Prints to the console.
  2028.  *
  2029.  *----------------------------------------------------------------------
  2030.  */
  2031.  
  2032. void
  2033. Recov_PrintState()
  2034. {
  2035.     Hash_Search            hashSearch;
  2036.     register Hash_Entry        *hashEntryPtr;
  2037.     register RecovHostState    *hostPtr;
  2038.     char            hostName[128];
  2039.     Time_Parts            timeParts;
  2040.     Time            bootTime;
  2041.     int                localOffset; /* minute offset for our tz */
  2042.     Time            currentTime;
  2043.  
  2044.     printf("RECOVERY STATE\n");
  2045.     Hash_StartSearch(&hashSearch);
  2046.     for (hashEntryPtr = Hash_Next(recovHashTable, &hashSearch);
  2047.      hashEntryPtr != (Hash_Entry *)NIL;
  2048.      hashEntryPtr = Hash_Next(recovHashTable, &hashSearch)) {
  2049.     hostPtr = (RecovHostState *)hashEntryPtr->value;
  2050.     if (hostPtr != (RecovHostState *)NIL) {
  2051.  
  2052.         Net_SpriteIDToName(hostPtr->spriteID, 128, hostName);
  2053.         printf("%-14s %-8s", hostName, GetState(hostPtr->state));
  2054.         printf(" bootID 0x%8x", hostPtr->bootID);
  2055.  
  2056.         /*
  2057.          * Print out boot time in our timezone.
  2058.          */
  2059.         Timer_GetTimeOfDay(¤tTime, &localOffset, (Boolean *) NIL);
  2060.         bootTime.seconds = hostPtr->bootID;
  2061.         bootTime.microseconds = 0;
  2062.         bootTime.seconds += (localOffset * 60);
  2063.         Time_ToParts(bootTime.seconds, FALSE, &timeParts);
  2064.         timeParts.month++;    /* So Jan is 1, not 0 */
  2065.         printf(" %d/%d/%d %d:%02d:%02d ", timeParts.month,
  2066.             timeParts.dayOfMonth,
  2067.             timeParts.year, timeParts.hours, timeParts.minutes,
  2068.             timeParts.seconds);
  2069.  
  2070.         /*
  2071.          * Print seconds ago we last heard from host.
  2072.          */
  2073.         printf("    %d ", currentTime.seconds - hostPtr->time.seconds);
  2074.         PrintExtraState(hostPtr);
  2075.         printf("\n");
  2076.     }
  2077.     }
  2078.     return;
  2079. }
  2080.  
  2081. /*
  2082.  *----------------------------------------------------------------------
  2083.  *
  2084.  * GetState --
  2085.  *
  2086.  *    Return a printable string for the host's state.
  2087.  *
  2088.  * Results:
  2089.  *    A pointer to a string.
  2090.  *
  2091.  * Side effects:
  2092.  *    None.
  2093.  *
  2094.  *----------------------------------------------------------------------
  2095.  */
  2096.  
  2097. static char *
  2098. GetState(state)
  2099.     int state;
  2100. {
  2101.     switch(state & (RECOV_HOST_ALIVE|RECOV_HOST_DEAD|RECOV_HOST_BOOTING)) {
  2102.     default:
  2103.     case RECOV_STATE_UNKNOWN:
  2104.         return("Unknown");
  2105.     case RECOV_HOST_ALIVE:
  2106.         return("Alive");
  2107.     case RECOV_HOST_BOOTING:
  2108.         return("Booting");
  2109.     case RECOV_HOST_DEAD:
  2110.         return("Dead");
  2111.     }
  2112. }
  2113.  
  2114. /*
  2115.  *----------------------------------------------------------------------
  2116.  *
  2117.  * RecovExtraState --
  2118.  *
  2119.  *    Prints out strings for various auxilliary state bits.
  2120.  *
  2121.  * Results:
  2122.  *    None.
  2123.  *
  2124.  * Side effects:
  2125.  *    Prints out stuff.
  2126.  *
  2127.  *----------------------------------------------------------------------
  2128.  */
  2129. static void
  2130. PrintExtraState(hostPtr)
  2131.     RecovHostState *hostPtr;
  2132. {
  2133.     if (hostPtr->state & RECOV_CRASH_CALLBACKS) {
  2134.     printf("Crash callbacks ");
  2135.     }
  2136.     if (hostPtr->state & RECOV_WANT_RECOVERY) {
  2137.     printf("Want recovery ");
  2138.     }
  2139.     if (hostPtr->state & RECOV_REBOOT_CALLBACKS) {
  2140.     printf("Reboot callbacks ");
  2141.     }
  2142.     if (hostPtr->state & RECOV_FAILURE) {
  2143.     printf("Failure ");
  2144.     }
  2145.     if (hostPtr->clientState & CLT_RECOV_IN_PROGRESS) {
  2146.     printf("Clt-inprogress ");
  2147.     }
  2148.     if (hostPtr->clientState & SRV_RECOV_IN_PROGRESS) {
  2149.     printf("Srv-inprogress ");
  2150.     }
  2151. }
  2152.  
  2153.  
  2154. void
  2155. Recov_ChangePrintLevel(newLevel)
  2156.     int    newLevel;
  2157. {
  2158.     recov_PrintLevel = newLevel;
  2159.     return;
  2160. }
  2161.  
  2162.  
  2163. /*
  2164.  *----------------------------------------------------------------------
  2165.  *
  2166.  * Recov_InitServerDriven --
  2167.  *
  2168.  *    Initialize system to use server-driven recovery.
  2169.  *
  2170.  * Results:
  2171.  *    None.
  2172.  *
  2173.  * Side effects:
  2174.  *    Turns on this kind of server recovery.
  2175.  *
  2176.  *----------------------------------------------------------------------
  2177.  */
  2178. void
  2179. Recov_InitServerDriven()
  2180. {
  2181.     recov_ServerDriven = TRUE;
  2182.     printf("Recov_InitServerDriven called.\n");
  2183.     if (recov_ServerDriven && recov_Transparent) {
  2184.     printf("Recov_InitServerDriven: can't do transparent recovery too.\n");
  2185.     printf("\tTurning it off!\n");
  2186.     recov_Transparent = FALSE;
  2187.     }
  2188.  
  2189.     return;
  2190. }
  2191. /*
  2192.  *----------------------------------------------------------------------
  2193.  *
  2194.  * Recov_StopServerDriven --
  2195.  *
  2196.  *    Stop system from using server-driven recovery.
  2197.  *
  2198.  * Results:
  2199.  *    None.
  2200.  *
  2201.  * Side effects:
  2202.  *    Turns off this kind of server recovery.
  2203.  *
  2204.  *----------------------------------------------------------------------
  2205.  */
  2206. void
  2207. Recov_StopServerDriven()
  2208. {
  2209.     recov_ServerDriven = FALSE;
  2210.     printf("Recov_StopServerDriven called.\n");
  2211.  
  2212.     return;
  2213. }
  2214.  
  2215. /*
  2216.  *----------------------------------------------------------------------
  2217.  *
  2218.  * Recov_StartServerDrivenRecovery --
  2219.  *
  2220.  *    Kick off server-driven recovery on client.
  2221.  *
  2222.  * Results:
  2223.  *    None.
  2224.  *
  2225.  * Side effects:
  2226.  *    Starts recovery.
  2227.  *
  2228.  *----------------------------------------------------------------------
  2229.  */
  2230. void
  2231. Recov_StartServerDrivenRecovery(serverID)
  2232.     int        serverID;    /* ID of server requesting recovery. */
  2233. {
  2234.     Hash_Entry        *hashPtr;
  2235.     RecovHostState    *hostPtr;
  2236.  
  2237.     LOCK_MONITOR;
  2238.     /* Set flag saying server-driven recovery is in progress. */
  2239.     hashPtr = Hash_Find(recovHashTable, (Address) serverID);
  2240.     if (hashPtr->value == (Address) NIL) {
  2241.     /*
  2242.      * Client may have been rebooted during server crash, so it may
  2243.      * not know about server when server contacts it for recovery.
  2244.      * That's why this isn't a panic.
  2245.      */
  2246.     printf("Recov_StartServerDrivenRecovery: don't know about server %d\n",
  2247.         serverID);
  2248.     printf("\tBut probably I should since it's trying to recover with me!");
  2249.     RECOV_INIT_HOST(hostPtr, serverID, RECOV_HOST_ALIVE, 0);
  2250.     hashPtr->value = (Address) hostPtr;
  2251.     RECOV_TRACE(serverID, RECOV_HOST_ALIVE, RECOV_CUZ_INIT);
  2252.     }
  2253.     hostPtr = (RecovHostState *)hashPtr->value;
  2254.     if (hostPtr->state & SRV_DRIVEN_IN_PROGRESS) {
  2255.     UNLOCK_MONITOR;
  2256.     panic("Server called us for server-driven recovery more than once.\n");
  2257.     }
  2258.     hostPtr->state |= SRV_DRIVEN_IN_PROGRESS;
  2259.     /* XX Test if client already blocked.   If not, panic.  XX */
  2260.     Sync_Broadcast(&hostPtr->waitForServer);
  2261.     UNLOCK_MONITOR;
  2262.  
  2263.     return;
  2264. }
  2265.  
  2266. /*
  2267.  *----------------------------------------------------------------------
  2268.  *
  2269.  * Recov_ServerStartingRecovery --
  2270.  *
  2271.  *    Mark that server-driven recovery has started, so that we
  2272.  *    can block out various rpc's.
  2273.  *
  2274.  * Results:
  2275.  *    None.
  2276.  *
  2277.  * Side effects:
  2278.  *    Blocks some rpcs.
  2279.  *
  2280.  *----------------------------------------------------------------------
  2281.  */
  2282. void
  2283. Recov_ServerStartingRecovery()
  2284. {
  2285.     LOCK_MONITOR;
  2286.     if (!recov_ServerDriven) {
  2287.     UNLOCK_MONITOR;
  2288.     panic("Recov_ServerStartingRecovery: server-driven not true!");
  2289.     }
  2290.     recov_BlockingRpcs = TRUE;
  2291.     UNLOCK_MONITOR;
  2292.  
  2293.     return;
  2294. }
  2295.  
  2296. /*
  2297.  *----------------------------------------------------------------------
  2298.  *
  2299.  * Recov_ServerFinishedRecovery --
  2300.  *
  2301.  *    Mark that server-driven recovery is finished, so that we
  2302.  *    can unblock various rpc's.
  2303.  *
  2304.  * Results:
  2305.  *    None.
  2306.  *
  2307.  * Side effects:
  2308.  *    Unblocks some rpcs.
  2309.  *
  2310.  *----------------------------------------------------------------------
  2311.  */
  2312. void
  2313. Recov_ServerFinishedRecovery()
  2314. {
  2315.     LOCK_MONITOR;
  2316.     if (!recov_ServerDriven) {
  2317.     UNLOCK_MONITOR;
  2318.     panic("Recov_ServerFinishedRecovery: server-driven not true!");
  2319.     }
  2320.     recov_BlockingRpcs = FALSE;
  2321.     /*
  2322.      * Before turning off blocking, we should check if all up clients have
  2323.      * recovered.  The "old" clients may not have.  If their state
  2324.      * is marked CLT_RECOV_IN_PROGRESS, or if their finished is not after
  2325.      * their start, then we're waiting for them to go through regular
  2326.      * recovery with us.  We should have a condition that client recovery
  2327.      * wakes up to check if it can turn off blocking.  But since we don't want
  2328.      * to wait forever, we'd have to have a timeout also.  But maybe the
  2329.      * easiest thing is to reboot everybody and not worry about backwards
  2330.      * compatibility??
  2331.      */
  2332.  
  2333.     UNLOCK_MONITOR;
  2334.  
  2335.     return;
  2336. }
  2337.  
  2338. /*
  2339.  *----------------------------------------------------------------------
  2340.  *
  2341.  * Recov_HoldForRecovery --
  2342.  *
  2343.  *    Are we blocking rpc's and is this an rpc that should be blocked out?
  2344.  *    This is called from Rpc_Dispatch, which means it's called at
  2345.  *    interrupt level, which means we can't grab a monitor lock, but
  2346.  *    that this should be okay.
  2347.  *
  2348.  * Results:
  2349.  *    True or false.
  2350.  *
  2351.  * Side effects:
  2352.  *    None.
  2353.  *
  2354.  *----------------------------------------------------------------------
  2355.  */
  2356. Boolean
  2357. Recov_HoldForRecovery(clientID, command)
  2358.     int            clientID;
  2359.     int            command;
  2360. {
  2361.     Hash_Entry        *hashPtr;
  2362.     RecovHostState    *hostPtr;
  2363.  
  2364.     if (!recov_BlockingRpcs) {
  2365.     return FALSE;
  2366.     }
  2367.     switch (command) {
  2368.     case RPC_FS_PREFIX:
  2369.     case RPC_FS_OPEN:
  2370.     case RPC_FS_READ:
  2371.     case RPC_FS_WRITE:
  2372.     case RPC_FS_CLOSE:
  2373.     case RPC_FS_UNLINK:
  2374.     case RPC_FS_RENAME:
  2375.     case RPC_FS_MKDIR:
  2376.     case RPC_FS_RMDIR:
  2377.     case RPC_FS_MKDEV:
  2378.     case RPC_FS_LINK:
  2379.     case RPC_FS_SYM_LINK:
  2380.     case RPC_FS_GET_ATTR:
  2381.     case RPC_FS_SET_ATTR:
  2382.     case RPC_FS_GET_ATTR_PATH:
  2383.     case RPC_FS_SET_ATTR_PATH:
  2384.     case RPC_FS_GET_IO_ATTR:
  2385.     case RPC_FS_SET_IO_ATTR:
  2386.     case RPC_FS_DEV_OPEN:
  2387.     case RPC_FS_SELECT:
  2388.     case RPC_FS_IO_CONTROL:
  2389.     /* Leave consistency rpc's unblocked for recovery. */
  2390.     case RPC_FS_MIGRATE:
  2391.     case RPC_FS_RELEASE:
  2392.     case RPC_PROC_MIG_COMMAND:
  2393.     case RPC_PROC_REMOTE_CALL:
  2394.     case RPC_PROC_REMOTE_WAIT:
  2395.     case RPC_FS_RELEASE_NEW:
  2396.     return TRUE;
  2397.     break;
  2398.     default:
  2399.     break;
  2400.     }
  2401.     /*
  2402.      * If host is not marked doing recovery right now, then ignore it.
  2403.      * We do this to avoid race conditions and deadlocks with some new
  2404.      * hosts trying to talk to the server while we're recovering old hosts.
  2405.      */
  2406.     if (!Mach_AtInterruptLevel()) {
  2407.     LOCK_MONITOR;
  2408.     }
  2409.     hashPtr = Hash_Find(recovHashTable, (Address) clientID);
  2410.     if (hashPtr->value == (Address) NIL) {
  2411.     RECOV_INIT_HOST(hostPtr, clientID, RECOV_STATE_UNKNOWN, 0);
  2412.     hashPtr->value = (Address) hostPtr;
  2413.     RECOV_TRACE(clientID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  2414. /* No, don't ignore it?? */
  2415.     if (!Mach_AtInterruptLevel()) {
  2416.         UNLOCK_MONITOR;
  2417.     }
  2418.     return TRUE;
  2419.     }
  2420.     hostPtr = (RecovHostState *)hashPtr->value;
  2421.     if ((hostPtr->clientState & CLT_DOING_SRV_RECOV) == 0) {
  2422.     if (!Mach_AtInterruptLevel()) {
  2423.         UNLOCK_MONITOR;
  2424.     }
  2425.     return TRUE;
  2426.     }
  2427.  
  2428.     if (!Mach_AtInterruptLevel()) {
  2429.     UNLOCK_MONITOR;
  2430.     }
  2431.     return FALSE;
  2432. }
  2433.  
  2434. /*
  2435.  *----------------------------------------------------------------------
  2436.  *
  2437.  * Recov_MarkOldClient --
  2438.  *
  2439.  *    Mark this client as one running an old kernel, and thus unable
  2440.  *    to allow server-drivven recovery.
  2441.  *
  2442.  * Results:
  2443.  *    None.
  2444.  *
  2445.  * Side effects:
  2446.  *    Marks state of client.
  2447.  *
  2448.  *----------------------------------------------------------------------
  2449.  */
  2450. void
  2451. Recov_MarkOldClient(clientID)
  2452.     int            clientID;
  2453. {
  2454.     Hash_Entry        *hashPtr;
  2455.     RecovHostState    *hostPtr;
  2456.  
  2457.     LOCK_MONITOR;
  2458.     hashPtr = Hash_Find(recovHashTable, (Address) clientID);
  2459.     if (hashPtr->value == (Address) NIL) {
  2460.     RECOV_INIT_HOST(hostPtr, clientID, RECOV_STATE_UNKNOWN, 0);
  2461.     hashPtr->value = (Address) hostPtr;
  2462.     RECOV_TRACE(clientID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  2463.     }
  2464.     hostPtr = (RecovHostState *)hashPtr->value;
  2465.     hostPtr->clientState |= CLT_OLD_RECOV;
  2466.  
  2467.     UNLOCK_MONITOR;
  2468.  
  2469.     return;
  2470. }
  2471.  
  2472.  
  2473.  
  2474. /*
  2475.  *----------------------------------------------------------------------
  2476.  *
  2477.  * Recov_WaitForServerDriven --
  2478.  *
  2479.  *    Make client wait for rpc from server telling it to start recovery.
  2480.  *    Also set a timeout in case server gets hosed and forgets us.
  2481.  *
  2482.  * Results:
  2483.  *    None.
  2484.  *
  2485.  * Side effects:
  2486.  *    Makes us wait for recovery.
  2487.  *
  2488.  *----------------------------------------------------------------------
  2489.  */
  2490. void
  2491. Recov_WaitForServerDriven(serverID)
  2492.     int            serverID;
  2493. {
  2494.     Hash_Entry        *hashPtr;
  2495.     RecovHostState    *hostPtr;
  2496.  
  2497.     LOCK_MONITOR;
  2498.     /*
  2499.      * Set something saying client is waiting for server, so that server
  2500.      * rpc can check this to make sure client is already waiting when
  2501.      * it wakes it?  For now, the client checks to see if server thing
  2502.      * already tried to wake it.  XXX  This isn't good enough, though, if
  2503.      * server recovery finishes and then client recovery tries again and sees
  2504.      * nothing going.
  2505.      */
  2506.     hashPtr = Hash_Find(recovHashTable, (Address) serverID);
  2507.     if (hashPtr->value == (Address) NIL) {
  2508.     panic("Recov_WaitForServer: should already know about this server.");
  2509.     }
  2510.     hostPtr = (RecovHostState *) hashPtr->value;
  2511.     /* Also set timeout so that if server forgets us, we'll be okay. XX */
  2512.     while ((hostPtr->state & SRV_DRIVEN_IN_PROGRESS) == 0) {
  2513.     (void) Sync_Wait(&hostPtr->waitForServer, FALSE);
  2514.     }
  2515.  
  2516.     UNLOCK_MONITOR;
  2517.  
  2518.     return;
  2519. }
  2520.  
  2521. /*
  2522.  *----------------------------------------------------------------------
  2523.  *
  2524.  * Recov_GetCurrentHostStates --
  2525.  *
  2526.  *    Get the current state of hosts we know about as a server.
  2527.  *
  2528.  * Results:
  2529.  *    Number of hosts in list.  A negative number if there wasn't enough
  2530.  *    buffer space.
  2531.  *
  2532.  * Side effects:
  2533.  *    Fills in buffer with hosts and their state.
  2534.  *
  2535.  *----------------------------------------------------------------------
  2536.  */
  2537. int
  2538. Recov_GetCurrentHostStates(infoBuffer, bufEntries)
  2539.     Dev_ClientInfo    *infoBuffer;    /* The array of info entries to fill. */
  2540.     int            bufEntries;    /* Number of available entries. */
  2541. {
  2542.     Hash_Entry        *hashPtr;
  2543.     RecovHostState    *hostPtr;
  2544.     Hash_Search        hashSearch;
  2545.     int            i;
  2546.  
  2547.     i = 0;
  2548.     Hash_StartSearch(&hashSearch);
  2549.     for (hashPtr = Hash_Next(recovHashTable, &hashSearch);
  2550.         hashPtr != (Hash_Entry *) NIL;
  2551.         hashPtr = Hash_Next(recovHashTable, &hashSearch)) {
  2552.     hostPtr = (RecovHostState *)hashPtr->value;
  2553.     if (hostPtr->state & RECOV_HOST_DEAD) {
  2554.          continue;
  2555.     }
  2556.     infoBuffer[i].hostNumber = hostPtr->spriteID;
  2557.     infoBuffer[i].hostState = DEV_CLIENT_STATE_NEW_HOST;
  2558.     i++;
  2559.     if (i >= bufEntries) {
  2560.         return -1;
  2561.     }
  2562.     }
  2563.  
  2564.     return i;
  2565. }
  2566.  
  2567. /*
  2568.  *----------------------------------------------------------------------
  2569.  *
  2570.  * Recov_MarkDoingServerRecovery --
  2571.  *
  2572.  *    Mark client state as doing server recovery.
  2573.  *
  2574.  * Results:
  2575.  *    None.
  2576.  *
  2577.  * Side effects:
  2578.  *    Marked.
  2579.  *
  2580.  *----------------------------------------------------------------------
  2581.  */
  2582. void
  2583. Recov_MarkDoingServerRecovery(clientID)
  2584.     int        clientID;    /* The client. */
  2585. {
  2586.     Hash_Entry        *hashPtr;
  2587.     RecovHostState    *hostPtr;
  2588.  
  2589.     LOCK_MONITOR;
  2590.     hashPtr = Hash_Find(recovHashTable, (Address) clientID);
  2591.     if (hashPtr->value == (Address) NIL) {
  2592.     RECOV_INIT_HOST(hostPtr, clientID, RECOV_STATE_UNKNOWN, 0);
  2593.     hashPtr->value = (Address) hostPtr;
  2594.     RECOV_TRACE(clientID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  2595.     }
  2596.     hostPtr = (RecovHostState *)hashPtr->value;
  2597.     hostPtr->clientState |= CLT_DOING_SRV_RECOV;
  2598.  
  2599.     UNLOCK_MONITOR;
  2600.  
  2601.     return;
  2602. }
  2603.  
  2604. /*
  2605.  *----------------------------------------------------------------------
  2606.  *
  2607.  * Recov_UnmarkDoingServerRecovery --
  2608.  *
  2609.  *    Mark client state as not doing server recovery.
  2610.  *
  2611.  * Results:
  2612.  *    None.
  2613.  *
  2614.  * Side effects:
  2615.  *    Marked.
  2616.  *
  2617.  *----------------------------------------------------------------------
  2618.  */
  2619. void
  2620. Recov_UnmarkDoingServerRecovery(clientID)
  2621.     int        clientID;    /* The client. */
  2622. {
  2623.     Hash_Entry        *hashPtr;
  2624.     RecovHostState    *hostPtr;
  2625.  
  2626.     LOCK_MONITOR;
  2627.     hashPtr = Hash_Find(recovHashTable, (Address) clientID);
  2628.     if (hashPtr->value == (Address) NIL) {
  2629.     printf("Recov_UnmarkDoingServerRecovery: don't know about client %d\n",
  2630.         clientID);
  2631.     RECOV_INIT_HOST(hostPtr, clientID, RECOV_STATE_UNKNOWN, 0);
  2632.     hashPtr->value = (Address) hostPtr;
  2633.     RECOV_TRACE(clientID, RECOV_STATE_UNKNOWN, RECOV_CUZ_INIT);
  2634.     }
  2635.     hostPtr = (RecovHostState *)hashPtr->value;
  2636.     hostPtr->clientState &= ~(CLT_DOING_SRV_RECOV);
  2637.  
  2638.     UNLOCK_MONITOR;
  2639.  
  2640.     return;
  2641. }
  2642.